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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h332
-rw-r--r--source/blender/blenkernel/BKE_action.h5
-rw-r--r--source/blender/blenkernel/BKE_anim.h45
-rw-r--r--source/blender/blenkernel/BKE_animsys.h44
-rw-r--r--source/blender/blenkernel/BKE_appdir.h2
-rw-r--r--source/blender/blenkernel/BKE_armature.h160
-rw-r--r--source/blender/blenkernel/BKE_blender_user_menu.h49
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h10
-rw-r--r--source/blender/blenkernel/BKE_blendfile.h7
-rw-r--r--source/blender/blenkernel/BKE_bmfont.h61
-rw-r--r--source/blender/blenkernel/BKE_brush.h18
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h19
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h5
-rw-r--r--source/blender/blenkernel/BKE_camera.h32
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h32
-rw-r--r--source/blender/blenkernel/BKE_cloth.h59
-rw-r--r--source/blender/blenkernel/BKE_collection.h199
-rw-r--r--source/blender/blenkernel/BKE_collision.h40
-rw-r--r--source/blender/blenkernel/BKE_constraint.h19
-rw-r--r--source/blender/blenkernel/BKE_context.h50
-rw-r--r--source/blender/blenkernel/BKE_crazyspace.h9
-rw-r--r--source/blender/blenkernel/BKE_curve.h23
-rw-r--r--source/blender/blenkernel/BKE_customdata.h58
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h12
-rw-r--r--source/blender/blenkernel/BKE_deform.h2
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h181
-rw-r--r--source/blender/blenkernel/BKE_displist.h32
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h16
-rw-r--r--source/blender/blenkernel/BKE_editmesh.h14
-rw-r--r--source/blender/blenkernel/BKE_editmesh_cache.h (renamed from source/blender/blenkernel/BKE_bullet.h)27
-rw-r--r--source/blender/blenkernel/BKE_editmesh_tangent.h40
-rw-r--r--source/blender/blenkernel/BKE_effect.h41
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h20
-rw-r--r--source/blender/blenkernel/BKE_fluidsim.h3
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h4
-rw-r--r--source/blender/blenkernel/BKE_global.h11
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h120
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h270
-rw-r--r--source/blender/blenkernel/BKE_group.h60
-rw-r--r--source/blender/blenkernel/BKE_icons.h51
-rw-r--r--source/blender/blenkernel/BKE_idprop.h11
-rw-r--r--source/blender/blenkernel/BKE_image.h16
-rw-r--r--source/blender/blenkernel/BKE_key.h14
-rw-r--r--source/blender/blenkernel/BKE_lamp.h2
-rw-r--r--source/blender/blenkernel/BKE_lattice.h52
-rw-r--r--source/blender/blenkernel/BKE_layer.h396
-rw-r--r--source/blender/blenkernel/BKE_library.h54
-rw-r--r--source/blender/blenkernel/BKE_library_override.h91
-rw-r--r--source/blender/blenkernel/BKE_library_query.h3
-rw-r--r--source/blender/blenkernel/BKE_library_remap.h2
-rw-r--r--source/blender/blenkernel/BKE_lightprobe.h (renamed from source/blender/blenkernel/BKE_bmfont_types.h)42
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h3
-rw-r--r--source/blender/blenkernel/BKE_main.h41
-rw-r--r--source/blender/blenkernel/BKE_mask.h7
-rw-r--r--source/blender/blenkernel/BKE_material.h21
-rw-r--r--source/blender/blenkernel/BKE_mball.h40
-rw-r--r--source/blender/blenkernel/BKE_mball_tessellate.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh.h163
-rw-r--r--source/blender/blenkernel/BKE_mesh_iterators.h67
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h28
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h122
-rw-r--r--source/blender/blenkernel/BKE_mesh_tangent.h68
-rw-r--r--source/blender/blenkernel/BKE_modifier.h166
-rw-r--r--source/blender/blenkernel/BKE_movieclip.h9
-rw-r--r--source/blender/blenkernel/BKE_multires.h90
-rw-r--r--source/blender/blenkernel/BKE_navmesh_conversion.h67
-rw-r--r--source/blender/blenkernel/BKE_nla.h12
-rw-r--r--source/blender/blenkernel/BKE_node.h62
-rw-r--r--source/blender/blenkernel/BKE_object.h165
-rw-r--r--source/blender/blenkernel/BKE_object_facemap.h53
-rw-r--r--source/blender/blenkernel/BKE_ocean.h6
-rw-r--r--source/blender/blenkernel/BKE_outliner_treehash.h6
-rw-r--r--source/blender/blenkernel/BKE_paint.h49
-rw-r--r--source/blender/blenkernel/BKE_particle.h98
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h15
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h20
-rw-r--r--source/blender/blenkernel/BKE_property.h53
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h19
-rw-r--r--source/blender/blenkernel/BKE_sca.h91
-rw-r--r--source/blender/blenkernel/BKE_scene.h102
-rw-r--r--source/blender/blenkernel/BKE_screen.h95
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h18
-rw-r--r--source/blender/blenkernel/BKE_shader_fx.h180
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h80
-rw-r--r--source/blender/blenkernel/BKE_sketch.h149
-rw-r--r--source/blender/blenkernel/BKE_smoke.h7
-rw-r--r--source/blender/blenkernel/BKE_softbody.h6
-rw-r--r--source/blender/blenkernel/BKE_sound.h8
-rw-r--r--source/blender/blenkernel/BKE_studiolight.h156
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h237
-rw-r--r--source/blender/blenkernel/BKE_subdiv_ccg.h249
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h127
-rw-r--r--source/blender/blenkernel/BKE_subdiv_foreach.h181
-rw-r--r--source/blender/blenkernel/BKE_subdiv_mesh.h56
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h1
-rw-r--r--source/blender/blenkernel/BKE_text.h4
-rw-r--r--source/blender/blenkernel/BKE_texture.h26
-rw-r--r--source/blender/blenkernel/BKE_tracking.h4
-rw-r--r--source/blender/blenkernel/BKE_unit.h13
-rw-r--r--source/blender/blenkernel/BKE_workspace.h110
-rw-r--r--source/blender/blenkernel/BKE_world.h4
-rw-r--r--source/blender/blenkernel/BKE_writeframeserver.h58
-rw-r--r--source/blender/blenkernel/CMakeLists.txt105
-rw-r--r--source/blender/blenkernel/depsgraph_private.h169
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c8
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c151
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c191
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c2914
-rw-r--r--source/blender/blenkernel/intern/action.c137
-rw-r--r--source/blender/blenkernel/intern/anim.c313
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c608
-rw-r--r--source/blender/blenkernel/intern/appdir.c34
-rw-r--r--source/blender/blenkernel/intern/armature.c705
-rw-r--r--source/blender/blenkernel/intern/armature_update.c154
-rw-r--r--source/blender/blenkernel/intern/blender.c24
-rw-r--r--source/blender/blenkernel/intern/blender_copybuffer.c19
-rw-r--r--source/blender/blenkernel/intern/blender_undo.c10
-rw-r--r--source/blender/blenkernel/intern/blender_user_menu.c121
-rw-r--r--source/blender/blenkernel/intern/blendfile.c121
-rw-r--r--source/blender/blenkernel/intern/bmfont.c293
-rw-r--r--source/blender/blenkernel/intern/boids.c3
-rw-r--r--source/blender/blenkernel/intern/bpath.c17
-rw-r--r--source/blender/blenkernel/intern/brush.c386
-rw-r--r--source/blender/blenkernel/intern/bullet.c97
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c474
-rw-r--r--source/blender/blenkernel/intern/cachefile.c37
-rw-r--r--source/blender/blenkernel/intern/camera.c122
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c2382
-rw-r--r--source/blender/blenkernel/intern/cloth.c760
-rw-r--r--source/blender/blenkernel/intern/collection.c1190
-rw-r--r--source/blender/blenkernel/intern/collision.c1612
-rw-r--r--source/blender/blenkernel/intern/colorband.c2
-rw-r--r--source/blender/blenkernel/intern/colortools.c115
-rw-r--r--source/blender/blenkernel/intern/constraint.c870
-rw-r--r--source/blender/blenkernel/intern/context.c201
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c68
-rw-r--r--source/blender/blenkernel/intern/curve.c173
-rw-r--r--source/blender/blenkernel/intern/customdata.c200
-rw-r--r--source/blender/blenkernel/intern/customdata_file.c10
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c407
-rw-r--r--source/blender/blenkernel/intern/deform.c44
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c3745
-rw-r--r--source/blender/blenkernel/intern/displist.c293
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c534
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c2320
-rw-r--r--source/blender/blenkernel/intern/editmesh.c86
-rw-r--r--source/blender/blenkernel/intern/editmesh_cache.c120
-rw-r--r--source/blender/blenkernel/intern/editmesh_tangent.c433
-rw-r--r--source/blender/blenkernel/intern/effect.c327
-rw-r--r--source/blender/blenkernel/intern/fcurve.c244
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c37
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c21
-rw-r--r--source/blender/blenkernel/intern/font.c123
-rw-r--r--source/blender/blenkernel/intern/freestyle.c14
-rw-r--r--source/blender/blenkernel/intern/gpencil.c1374
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c826
-rw-r--r--source/blender/blenkernel/intern/group.c379
-rw-r--r--source/blender/blenkernel/intern/icons.c259
-rw-r--r--source/blender/blenkernel/intern/icons_rasterize.c146
-rw-r--r--source/blender/blenkernel/intern/idcode.c81
-rw-r--r--source/blender/blenkernel/intern/idprop.c46
-rw-r--r--source/blender/blenkernel/intern/image.c326
-rw-r--r--source/blender/blenkernel/intern/ipo.c34
-rw-r--r--source/blender/blenkernel/intern/key.c252
-rw-r--r--source/blender/blenkernel/intern/lamp.c99
-rw-r--r--source/blender/blenkernel/intern/lattice.c141
-rw-r--r--source/blender/blenkernel/intern/layer.c1479
-rw-r--r--source/blender/blenkernel/intern/layer_utils.c125
-rw-r--r--source/blender/blenkernel/intern/library.c731
-rw-r--r--source/blender/blenkernel/intern/library_idmap.c1
-rw-r--r--source/blender/blenkernel/intern/library_override.c789
-rw-r--r--source/blender/blenkernel/intern/library_query.c303
-rw-r--r--source/blender/blenkernel/intern/library_remap.c204
-rw-r--r--source/blender/blenkernel/intern/lightprobe.c101
-rw-r--r--source/blender/blenkernel/intern/linestyle.c15
-rw-r--r--source/blender/blenkernel/intern/main.c446
-rw-r--r--source/blender/blenkernel/intern/mask.c59
-rw-r--r--source/blender/blenkernel/intern/mask_evaluate.c17
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c14
-rw-r--r--source/blender/blenkernel/intern/material.c1242
-rw-r--r--source/blender/blenkernel/intern/mball.c230
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c42
-rw-r--r--source/blender/blenkernel/intern/mesh.c492
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c547
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c273
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c211
-rw-r--r--source/blender/blenkernel/intern/mesh_merge.c685
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c197
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c380
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c716
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c236
-rw-r--r--source/blender/blenkernel/intern/modifier.c171
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c249
-rw-r--r--source/blender/blenkernel/intern/movieclip.c48
-rw-r--r--source/blender/blenkernel/intern/multires.c546
-rw-r--r--source/blender/blenkernel/intern/multires_inline.h68
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.c1206
-rw-r--r--source/blender/blenkernel/intern/multires_subdiv.c67
-rw-r--r--source/blender/blenkernel/intern/navmesh_conversion.c502
-rw-r--r--source/blender/blenkernel/intern/nla.c79
-rw-r--r--source/blender/blenkernel/intern/node.c265
-rw-r--r--source/blender/blenkernel/intern/object.c1471
-rw-r--r--source/blender/blenkernel/intern/object_deform.c17
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c503
-rw-r--r--source/blender/blenkernel/intern/object_facemap.c257
-rw-r--r--source/blender/blenkernel/intern/object_update.c269
-rw-r--r--source/blender/blenkernel/intern/ocean.c93
-rw-r--r--source/blender/blenkernel/intern/outliner_treehash.c69
-rw-r--r--source/blender/blenkernel/intern/packedFile.c28
-rw-r--r--source/blender/blenkernel/intern/paint.c467
-rw-r--r--source/blender/blenkernel/intern/paint_toolslots.c140
-rw-r--r--source/blender/blenkernel/intern/particle.c1198
-rw-r--r--source/blender/blenkernel/intern/particle_child.c50
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c490
-rw-r--r--source/blender/blenkernel/intern/particle_system.c300
-rw-r--r--source/blender/blenkernel/intern/pbvh.c176
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c22
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h5
-rw-r--r--source/blender/blenkernel/intern/pointcache.c107
-rw-r--r--source/blender/blenkernel/intern/property.c267
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c590
-rw-r--r--source/blender/blenkernel/intern/sca.c1178
-rw-r--r--source/blender/blenkernel/intern/scene.c1649
-rw-r--r--source/blender/blenkernel/intern/screen.c473
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c70
-rw-r--r--source/blender/blenkernel/intern/sequencer.c74
-rw-r--r--source/blender/blenkernel/intern/shader_fx.c245
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c1027
-rw-r--r--source/blender/blenkernel/intern/sketch.c555
-rw-r--r--source/blender/blenkernel/intern/smoke.c470
-rw-r--r--source/blender/blenkernel/intern/softbody.c250
-rw-r--r--source/blender/blenkernel/intern/sound.c168
-rw-r--r--source/blender/blenkernel/intern/studiolight.c1242
-rw-r--r--source/blender/blenkernel/intern/subdiv.c149
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c1188
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg_mask.c197
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter.c77
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter.h67
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter_mesh.c410
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement.c46
-rw-r--r--source/blender/blenkernel/intern/subdiv_displacement_multires.c358
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c394
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c2038
-rw-r--r--source/blender/blenkernel/intern/subdiv_inline.h80
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c1148
-rw-r--r--source/blender/blenkernel/intern/subdiv_stats.c92
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2302
-rw-r--r--source/blender/blenkernel/intern/text.c3
-rw-r--r--source/blender/blenkernel/intern/texture.c441
-rw-r--r--source/blender/blenkernel/intern/tracking.c7
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c14
-rw-r--r--source/blender/blenkernel/intern/undo_system.c11
-rw-r--r--source/blender/blenkernel/intern/unit.c236
-rw-r--r--source/blender/blenkernel/intern/workspace.c446
-rw-r--r--source/blender/blenkernel/intern/world.c48
-rw-r--r--source/blender/blenkernel/intern/writeavi.c17
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c39
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c419
-rw-r--r--source/blender/blenkernel/nla_private.h18
260 files changed, 37849 insertions, 32844 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 89f3431fec8..baec7e77328 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -85,18 +85,13 @@ struct CCGKey;
struct MVert;
struct MEdge;
struct MFace;
-struct MTFace;
struct Object;
struct Scene;
struct Mesh;
struct MLoopNorSpaceArray;
struct BMEditMesh;
-struct KeyBlock;
struct ModifierData;
-struct MCol;
-struct ColorBand;
-struct GPUVertexAttribs;
-struct GPUDrawObject;
+struct Depsgraph;
struct PBVH;
/* number of sub-elements each mesh element has (for interpolation) */
@@ -122,40 +117,9 @@ typedef struct DMFlagMat {
typedef enum DerivedMeshType {
DM_TYPE_CDDM,
- DM_TYPE_EDITBMESH,
DM_TYPE_CCGDM
} DerivedMeshType;
-typedef enum DMDrawOption {
- /* the element is hidden or otherwise non-drawable */
- DM_DRAW_OPTION_SKIP = 0,
- /* normal drawing */
- DM_DRAW_OPTION_NORMAL = 1,
- /* draw, but don't set the color from mcol */
- DM_DRAW_OPTION_NO_MCOL = 2,
- /* used in drawMappedFaces, use GL stipple for the face */
- DM_DRAW_OPTION_STIPPLE = 3,
-} DMDrawOption;
-
-/* Drawing callback types */
-typedef int (*DMSetMaterial)(int mat_nr, void *attribs);
-typedef int (*DMCompareDrawOptions)(void *userData, int cur_index, int next_index);
-typedef void (*DMSetDrawInterpOptions)(void *userData, int index, float t);
-typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index);
-typedef DMDrawOption (*DMSetDrawOptionsMappedTex)(void *userData, int origindex, int mat_nr);
-typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTexPoly *mtexpoly, const bool has_vcol, int matnr);
-
-typedef enum DMDrawFlag {
- DM_DRAW_USE_COLORS = (1 << 0),
- DM_DRAW_ALWAYS_SMOOTH = (1 << 1),
- DM_DRAW_USE_ACTIVE_UV = (1 << 2),
- DM_DRAW_USE_TEXPAINT_UV = (1 << 3),
- DM_DRAW_SKIP_HIDDEN = (1 << 4),
- DM_DRAW_SKIP_SELECT = (1 << 5),
- DM_DRAW_SELECT_USE_EDITMODE = (1 << 6),
- DM_DRAW_NEED_NORMALS = (1 << 7)
-} DMDrawFlag;
-
typedef enum DMForeachFlag {
DM_FOREACH_NOP = 0,
DM_FOREACH_USE_NORMAL = (1 << 0), /* foreachMappedVert, foreachMappedLoop, foreachMappedFaceCenter */
@@ -164,14 +128,9 @@ typedef enum DMForeachFlag {
typedef enum DMDirtyFlag {
/* dm has valid tessellated faces, but tessellated CDDATA need to be updated. */
DM_DIRTY_TESS_CDLAYERS = 1 << 0,
- /* One of the MCOL layers have been updated, force updating of GPUDrawObject's colors buffer.
- * This is necessary with modern, VBO draw code, as e.g. in vpaint mode me->mcol may be updated
- * without actually rebuilding dm (hence by default keeping same GPUDrawObject, and same colors
- * buffer, which prevents update during a stroke!). */
- DM_DIRTY_MCOL_UPDATE_DRAW = 1 << 1,
/* check this with modifier dependsOnNormals callback to see if normals need recalculation */
- DM_DIRTY_NORMALS = 1 << 2,
+ DM_DIRTY_NORMALS = 1 << 1,
} DMDirtyFlag;
typedef struct DerivedMesh DerivedMesh;
@@ -182,9 +141,7 @@ struct DerivedMesh {
int needsFree; /* checked on ->release, is set to 0 for cached results */
int deformedOnly; /* set by modifier stack if only deformed from original */
BVHCache *bvhCache;
- struct GPUDrawObject *drawObject;
DerivedMeshType type;
- float auto_bump_scale;
DMDirtyFlag dirty;
int totmat; /* total materials. Will be valid only before object drawing. */
struct Material **mat; /* material array. Will be valid only before object drawing */
@@ -384,117 +341,6 @@ struct DerivedMesh {
*/
struct PBVH *(*getPBVH)(struct Object *ob, DerivedMesh *dm);
- /* Drawing Operations */
-
- /** Draw all vertices as bgl points (no options) */
- void (*drawVerts)(DerivedMesh *dm);
-
- /** Draw edges in the UV mesh (if exists) */
- void (*drawUVEdges)(DerivedMesh *dm);
-
- /** Draw all edges as lines (no options)
- *
- * Also called for *final* editmode DerivedMeshes
- */
- void (*drawEdges)(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges);
-
- /** Draw all loose edges (edges w/ no adjoining faces) */
- void (*drawLooseEdges)(DerivedMesh *dm);
-
- /** Draw all faces
- * o Set face normal or vertex normal based on inherited face flag
- * o Use inherited face material index to call setMaterial
- * o Only if setMaterial returns true
- *
- * Also called for *final* editmode DerivedMeshes
- */
- void (*drawFacesSolid)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
- bool fast, DMSetMaterial setMaterial);
-
- /** Draw all faces using MTFace
- * - Drawing options too complicated to enumerate, look at code.
- */
- void (*drawFacesTex)(DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag);
-
- /** Draw all faces with GLSL materials
- * o setMaterial is called for every different material nr
- * o Only if setMaterial returns true
- */
- void (*drawFacesGLSL)(DerivedMesh *dm, DMSetMaterial setMaterial);
-
- /** Draw mapped faces (no color, or texture)
- * - Only if !setDrawOptions or
- * setDrawOptions(userData, mapped-face-index, r_drawSmooth)
- * returns true
- *
- * If drawSmooth is set to true then vertex normals should be set and
- * glShadeModel called with GL_SMOOTH. Otherwise the face normal should
- * be set and glShadeModel called with GL_FLAT.
- *
- * The setDrawOptions is allowed to not set drawSmooth (for example, when
- * lighting is disabled), in which case the implementation should draw as
- * smooth shaded.
- */
- void (*drawMappedFaces)(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- DMCompareDrawOptions compareDrawOptions,
- void *userData,
- DMDrawFlag flag);
-
- /** Draw mapped faces using MTFace
- * - Drawing options too complicated to enumerate, look at code.
- */
- void (*drawMappedFacesTex)(DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag);
-
- /** Draw mapped faces with GLSL materials
- * - setMaterial is called for every different material nr
- * - setDrawOptions is called for every face
- * - Only if setMaterial and setDrawOptions return true
- */
- void (*drawMappedFacesGLSL)(DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData);
-
- /** Draw mapped edges as lines
- * - Only if !setDrawOptions or setDrawOptions(userData, mapped-edge)
- * returns true
- */
- void (*drawMappedEdges)(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- void *userData);
-
- /** Draw mapped edges as lines with interpolation values
- * - Only if !setDrawOptions or
- * setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t)
- * returns true
- *
- * NOTE: This routine is optional!
- */
- void (*drawMappedEdgesInterp)(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetDrawInterpOptions setDrawInterpOptions,
- void *userData);
-
- /** Draw all faces with materials
- * - setMaterial is called for every different material nr
- * - setFace is called to verify if a face must be hidden
- */
- void (*drawMappedFacesMat)(DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData);
-
- struct GPUDrawObject *(*gpuObjectNew)(DerivedMesh *dm);
- void (*copy_gpu_data)(DerivedMesh *dm, int type, void *varray_p,
- const int *mat_orig_to_new, const void *user_data);
-
/** Release reference to the DerivedMesh. This function decides internally
* if the DerivedMesh will be freed, or cached for later use. */
void (*release)(DerivedMesh *dm);
@@ -526,17 +372,6 @@ int DM_release(DerivedMesh *dm);
*/
void DM_to_mesh(DerivedMesh *dm, struct Mesh *me, struct Object *ob, CustomDataMask mask, bool take_ownership);
-struct BMEditMesh *DM_to_editbmesh(
- struct DerivedMesh *dm,
- struct BMEditMesh *existing, const bool do_tessellate);
-
-/* conversion to bmesh only */
-void DM_to_bmesh_ex(struct DerivedMesh *dm, struct BMesh *bm, const bool calc_face_normal);
-struct BMesh *DM_to_bmesh(struct DerivedMesh *dm, const bool calc_face_normal);
-
-
-/** Utility function to convert a DerivedMesh to a shape key block */
-void DM_to_meshkey(DerivedMesh *dm, struct Mesh *me, struct KeyBlock *kb);
void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask);
@@ -546,19 +381,19 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask);
* freed, see BKE_customdata.h for the different options
*/
void DM_add_vert_layer(
- struct DerivedMesh *dm, int type, int alloctype,
+ struct DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
void DM_add_edge_layer(
- struct DerivedMesh *dm, int type, int alloctype,
+ struct DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
void DM_add_tessface_layer(
- struct DerivedMesh *dm, int type, int alloctype,
+ struct DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
void DM_add_loop_layer(
- DerivedMesh *dm, int type, int alloctype,
+ DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
void DM_add_poly_layer(
- struct DerivedMesh *dm, int type, int alloctype,
+ struct DerivedMesh *dm, int type, eCDAllocType alloctype,
void *layer);
/* custom data access functions
@@ -624,16 +459,8 @@ void DM_free_poly_data(struct DerivedMesh *dm, int index, int count);
void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
void DM_ensure_normals(DerivedMesh *dm);
-void DM_ensure_tessface(DerivedMesh *dm);
void DM_ensure_looptri_data(DerivedMesh *dm);
-void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num);
-
-void DM_update_tessface_data(DerivedMesh *dm);
-void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate);
-
-void DM_update_materials(DerivedMesh *dm, struct Object *ob);
-struct MLoopUV *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr);
void DM_interp_vert_data(
struct DerivedMesh *source, struct DerivedMesh *dest,
@@ -654,8 +481,6 @@ void DM_interp_tessface_data(
float *weights, FaceVertWeight *vert_weights,
int count, int dest_index);
-void DM_swap_tessface_data(struct DerivedMesh *dm, int index, const int *corner_indices);
-
void DM_interp_loop_data(
struct DerivedMesh *source, struct DerivedMesh *dest,
int *src_indices,
@@ -666,146 +491,51 @@ void DM_interp_poly_data(
int *src_indices,
float *weights, int count, int dest_index);
-/* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */
-void vDM_ColorBand_store(const struct ColorBand *coba, const char alert_color[4]);
-
-/* UNUSED */
-#if 0
-/** Simple function to get me->totvert amount of vertices/normals,
- * correctly deformed and subsurfered. Needed especially when vertexgroups are involved.
- * In use now by vertex/weight paint and particles */
-DMCoNo *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob);
-#endif
-void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos);
-/* */
-DerivedMesh *mesh_get_derived_final(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask);
-DerivedMesh *mesh_get_derived_deform(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask);
+void mesh_get_mapped_verts_coords(struct Mesh *me_eval, float (*r_cos)[3], const int totcos);
DerivedMesh *mesh_create_derived_for_modifier(
- struct Scene *scene, struct Object *ob,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
struct ModifierData *md, int build_shapekey_layers);
DerivedMesh *mesh_create_derived_render(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask);
-
-DerivedMesh *getEditDerivedBMesh(
- struct BMEditMesh *em, struct Object *ob, CustomDataMask data_mask,
- float (*vertexCos)[3]);
-
-DerivedMesh *mesh_create_derived_index_render(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask, int index);
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
/* same as above but wont use render settings */
DerivedMesh *mesh_create_derived(struct Mesh *me, float (*vertCos)[3]);
-DerivedMesh *mesh_create_derived_view(
- struct Scene *scene, struct Object *ob,
- CustomDataMask dataMask);
DerivedMesh *mesh_create_derived_no_deform(
- struct Scene *scene, struct Object *ob,
- float (*vertCos)[3],
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, float (*vertCos)[3],
CustomDataMask dataMask);
DerivedMesh *mesh_create_derived_no_deform_render(
- struct Scene *scene, struct Object *ob,
- float (*vertCos)[3],
- CustomDataMask dataMask);
-/* for gameengine */
-DerivedMesh *mesh_create_derived_no_virtual(
- struct Scene *scene, struct Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask);
-DerivedMesh *mesh_create_derived_physics(
- struct Scene *scene, struct Object *ob, float (*vertCos)[3],
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, float (*vertCos)[3],
CustomDataMask dataMask);
-DerivedMesh *editbmesh_get_derived_base(
- struct Object *ob, struct BMEditMesh *em, CustomDataMask data_mask);
-DerivedMesh *editbmesh_get_derived_cage(
- struct Scene *scene, struct Object *,
+struct Mesh *editbmesh_get_eval_cage(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *,
struct BMEditMesh *em, CustomDataMask dataMask);
-DerivedMesh *editbmesh_get_derived_cage_and_final(
- struct Scene *scene, struct Object *,
+struct Mesh *editbmesh_get_eval_cage_and_final(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *,
struct BMEditMesh *em, CustomDataMask dataMask,
- DerivedMesh **r_final);
-
-DerivedMesh *object_get_derived_final(struct Object *ob, const bool for_render);
+ struct Mesh **r_final);
float (*editbmesh_get_vertex_cos(struct BMEditMesh *em, int *r_numVerts))[3];
-bool editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm);
+bool editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, bool has_prev_mesh);
void makeDerivedMesh(
- struct Scene *scene, struct Object *ob, struct BMEditMesh *em,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct BMEditMesh *em,
CustomDataMask dataMask, const bool build_shapekey_layers);
-void weight_to_rgb(float r_rgb[3], const float weight);
-/** Update the weight MCOL preview layer.
- * If weights are NULL, use object's active vgroup(s).
- * Else, weights must be an array of weight float values.
- * If indices is NULL, it must be of numVerts length.
- * Else, it must be of num length, as indices, which contains vertices' idx to apply weights to.
- * (other vertices are assumed zero weight).
- */
-void DM_update_weight_mcol(
- struct Object *ob, struct DerivedMesh *dm, int const draw_flag,
- float *weights, int num, const int *indices);
-
-/** convert layers requested by a GLSL material to actually available layers in
- * the DerivedMesh, with both a pointer for arrays and an offset for editmesh */
-typedef struct DMVertexAttribs {
- struct {
- struct MLoopUV *array;
- int em_offset, gl_index, gl_texco, gl_info_index;
- } tface[MAX_MTFACE];
-
- struct {
- struct MLoopCol *array;
- int em_offset, gl_index, gl_info_index;
- } mcol[MAX_MCOL];
-
- struct {
- float (*array)[4];
- int em_offset, gl_index, gl_info_index;
- } tang[MAX_MTFACE];
-
- struct {
- float (*array)[3];
- int em_offset, gl_index, gl_texco, gl_info_index;
- } orco;
-
- int tottface, totmcol, tottang, totorco;
-} DMVertexAttribs;
-
-void DM_vertex_attributes_from_gpu(
- DerivedMesh *dm,
- struct GPUVertexAttribs *gattribs, DMVertexAttribs *attribs);
-
-void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop);
-void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs);
-
-void DM_calc_tangents_names_from_gpu(
- const struct GPUVertexAttribs *gattribs,
- char (*tangent_names)[MAX_NAME], int *tangent_names_count);
void DM_add_named_tangent_layer_for_uv(
CustomData *uv_data, CustomData *tan_data, int numLoopData,
const char *layer_name);
-#define DM_TANGENT_MASK_ORCO (1 << 9)
-void DM_calc_loop_tangents_step_0(
- const CustomData *loopData, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count,
- bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
- char *ract_uv_name, char *rren_uv_name, short *rtangent_mask);
void DM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent, const char (*tangent_names)[MAX_NAME],
int tangent_names_count);
-void DM_calc_auto_bump_scale(DerivedMesh *dm);
-/** Set object's bounding box based on DerivedMesh min/max data */
-void DM_set_object_boundbox(struct Object *ob, DerivedMesh *dm);
+void DM_calc_auto_bump_scale(DerivedMesh *dm);
void DM_init_origspace(DerivedMesh *dm);
@@ -818,20 +548,4 @@ void DM_debug_print_cdlayers(CustomData *cdata);
bool DM_is_valid(DerivedMesh *dm);
#endif
-BLI_INLINE int DM_origindex_mface_mpoly(
- const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i) ATTR_NONNULL(1);
-
-BLI_INLINE int DM_origindex_mface_mpoly(
- const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i)
-{
- const int j = index_mf_to_mpoly[i];
- return (j != ORIGINDEX_NONE) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : ORIGINDEX_NONE;
-}
-
-struct MVert *DM_get_vert_array(struct DerivedMesh *dm, bool *r_allocated);
-struct MEdge *DM_get_edge_array(struct DerivedMesh *dm, bool *r_allocated);
-struct MLoop *DM_get_loop_array(struct DerivedMesh *dm, bool *r_allocated);
-struct MPoly *DM_get_poly_array(struct DerivedMesh *dm, bool *r_allocated);
-struct MFace *DM_get_tessface_array(struct DerivedMesh *dm, bool *r_allocated);
-
#endif /* __BKE_DERIVEDMESH_H__ */
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index b627e3f69e8..882078e6e99 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -163,9 +163,6 @@ struct bPoseChannel *BKE_pose_channel_get_mirrored(const struct bPose *pose, con
bool BKE_pose_channels_is_valid(const struct bPose *pose);
#endif
-/* Copy the data from the action-pose (src) into the pose */
-void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
-
/* sets constraint flags */
void BKE_pose_update_constraint_flags(struct bPose *pose);
@@ -204,6 +201,7 @@ void BKE_pose_remove_group_index(struct bPose *pose, const int index);
void what_does_obaction(struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe);
/* for proxy */
+void BKE_pose_copyesult_pchan_result(struct bPoseChannel *pchanto, const struct bPoseChannel *pchanfrom);
bool BKE_pose_copy_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void BKE_pose_rest(struct bPose *pose);
@@ -211,6 +209,7 @@ void BKE_pose_rest(struct bPose *pose);
/* Tag pose for recalc. Also tag all related data to be recalc. */
void BKE_pose_tag_recalc(struct Main *bmain, struct bPose *pose);
+
#ifdef __cplusplus
};
#endif
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h
index 05717e3c8af..0d8a50c5325 100644
--- a/source/blender/blenkernel/BKE_anim.h
+++ b/source/blender/blenkernel/BKE_anim.h
@@ -35,10 +35,11 @@
struct bAnimVizSettings;
struct bMotionPath;
struct bPoseChannel;
-struct EvaluationContext;
+struct Depsgraph;
struct ListBase;
struct Main;
struct Object;
+struct ParticleSystem;
struct Path;
struct ReportList;
struct Scene;
@@ -48,13 +49,20 @@ struct Scene;
void animviz_settings_init(struct bAnimVizSettings *avs);
+struct bMotionPath *animviz_copy_motionpath(const struct bMotionPath *mpath_src);
+
void animviz_free_motionpath_cache(struct bMotionPath *mpath);
void animviz_free_motionpath(struct bMotionPath *mpath);
struct bMotionPath *animviz_verify_motionpaths(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan);
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
-void animviz_calc_motionpaths(struct Main *bmain, struct Scene *scene, ListBase *targets);
+void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
+ struct Main *bmain,
+ struct Scene *scene,
+ ListBase *targets,
+ bool restore,
+ bool current_frame_only);
/* ---------------------------------------------------- */
/* Curve Paths */
@@ -66,25 +74,28 @@ int where_on_path(struct Object *ob, float ctime, float vec[4], float dir[3], fl
/* ---------------------------------------------------- */
/* Dupli-Geometry */
-struct ListBase *object_duplilist_ex(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob, bool update);
-struct ListBase *object_duplilist(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *sce, struct Object *ob);
+struct ListBase *object_duplilist(struct Depsgraph *depsgraph, struct Scene *sce, struct Object *ob);
void free_object_duplilist(struct ListBase *lb);
int count_duplilist(struct Object *ob);
-typedef struct DupliExtraData {
- float obmat[4][4];
- unsigned int lay;
-} DupliExtraData;
+typedef struct DupliObject {
+ struct DupliObject *next, *prev;
+ struct Object *ob;
+ float mat[4][4];
+ float orco[3], uv[2];
+
+ short type; /* from Object.transflag */
+ char no_draw;
+
+ /* Persistent identifier for a dupli object, for inter-frame matching of
+ * objects with motion blur, or inter-update matching for syncing. */
+ int persistent_id[16]; /* 2*MAX_DUPLI_RECUR */
-typedef struct DupliApplyData {
- int num_objects;
- DupliExtraData *extra;
-} DupliApplyData;
+ /* Particle this dupli was generated from. */
+ struct ParticleSystem *particle_system;
-DupliApplyData *duplilist_apply(struct Object *ob, struct Scene *scene, struct ListBase *duplilist);
-void duplilist_restore(struct ListBase *duplilist, DupliApplyData *apply_data);
-void duplilist_free_apply_data(DupliApplyData *apply_data);
+ /* Random ID for shading */
+ unsigned int random_id;
+} DupliObject;
#endif
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 5cce1e090a9..394351d1df2 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -31,22 +31,23 @@
* \author Joshua Leung
*/
-struct ID;
-struct ListBase;
-struct Main;
struct AnimData;
+struct ChannelDriver;
+struct Depsgraph;
struct FCurve;
-struct KeyingSet;
+struct ID;
struct KS_Path;
+struct KeyingSet;
+struct ListBase;
+struct Main;
struct PathResolvedRNA;
-struct bContext;
-
struct PointerRNA;
struct PropertyRNA;
struct ReportList;
+struct Scene;
struct bAction;
struct bActionGroup;
-struct AnimMapper;
+struct bContext;
/* ************************************* */
/* AnimData API */
@@ -68,10 +69,10 @@ bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct b
void BKE_animdata_free(struct ID *id, const bool do_id_user);
/* Copy AnimData */
-struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const bool do_action);
+struct AnimData *BKE_animdata_copy(struct Main *bmain, struct AnimData *adt, const int flag);
/* Copy AnimData */
-bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, const bool do_action);
+bool BKE_animdata_copy_id(struct Main *bmain, struct ID *id_to, struct ID *id_from, const int flag);
/* Copy AnimData Actions */
void BKE_animdata_copy_id_action(struct Main *bmain, struct ID *id, const bool set_newid);
@@ -120,7 +121,7 @@ void BKE_keyingsets_free(struct ListBase *list);
/* Path Fixing API */
/* Get a "fixed" version of the given path (oldPath) */
-char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *prefix, const char *oldName,
+char *BKE_animsys_fix_rna_path_rename(struct ID *owner_id, char *old_path, const char *prefix, const char *oldName,
const char *newName, int oldSubscript, int newSubscript, bool verify_paths);
/* Fix all the paths for the given ID + Action */
@@ -133,7 +134,7 @@ void BKE_animdata_fix_paths_rename(struct ID *owner_id, struct AnimData *adt, st
bool verify_paths);
/* Fix all the paths for the entire database... */
-void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const char *oldName, const char *newName);
+void BKE_animdata_fix_paths_rename_all(struct ID *ref_id, const char *prefix, const char *oldName, const char *newName);
/* Fix the path after removing elements that are not ID (e.g., node) */
void BKE_animdata_fix_paths_remove(struct ID *id, const char *path);
@@ -151,7 +152,7 @@ char *BKE_animdata_driver_path_hack(struct bContext *C, struct PointerRNA *ptr,
char *base_path);
/* ************************************* */
-/* Batch AnimData API */
+/* GPUBatch AnimData API */
/* Define for callback looper used in BKE_animdata_main_cb */
typedef void (*ID_AnimData_Edit_Callback)(struct ID *id, struct AnimData *adt, void *user_data);
@@ -176,14 +177,13 @@ void BKE_fcurves_main_cb(struct Main *bmain, ID_FCurve_Edit_Callback func, void
/* In general, these ones should be called to do all animation evaluation */
/* Evaluation loop for evaluating animation data */
-void BKE_animsys_evaluate_animdata(struct Scene *scene, struct ID *id, struct AnimData *adt, float ctime, short recalc);
+void BKE_animsys_evaluate_animdata(struct Depsgraph *depsgraph, struct Scene *scene, struct ID *id, struct AnimData *adt, float ctime, short recalc);
/* Evaluation of all ID-blocks with Animation Data blocks - Animation Data Only */
-void BKE_animsys_evaluate_all_animation(struct Main *main, struct Scene *scene, float ctime);
+void BKE_animsys_evaluate_all_animation(struct Main *main, struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
/* TODO(sergey): This is mainly a temp public function. */
-struct FCurve;
-bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap, struct FCurve *fcu, float curval);
+bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct FCurve *fcu, float curval);
/* ------------ Specialized API --------------- */
/* There are a few special tools which require these following functions. They are NOT to be used
@@ -194,19 +194,21 @@ bool BKE_animsys_execute_fcurve(struct PointerRNA *ptr, struct AnimMapper *remap
*/
/* Evaluate Action (F-Curve Bag) */
-void animsys_evaluate_action(struct PointerRNA *ptr, struct bAction *act, struct AnimMapper *remap, float ctime);
+void animsys_evaluate_action(struct Depsgraph *depsgraph, struct PointerRNA *ptr, struct bAction *act, float ctime);
/* Evaluate Action Group */
-void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act, struct bActionGroup *agrp, struct AnimMapper *remap, float ctime);
+void animsys_evaluate_action_group(struct PointerRNA *ptr, struct bAction *act, struct bActionGroup *agrp, float ctime);
/* ************************************* */
/* ------------ Evaluation API --------------- */
-struct EvaluationContext;
+struct Depsgraph;
+
+void BKE_animsys_eval_animdata(struct Depsgraph *depsgraph, struct ID *id);
+void BKE_animsys_eval_driver(struct Depsgraph *depsgraph, struct ID *id, int driver_index, struct ChannelDriver *driver_orig);
-void BKE_animsys_eval_animdata(struct EvaluationContext *eval_ctx, struct ID *id);
-void BKE_animsys_eval_driver(struct EvaluationContext *eval_ctx, struct ID *id, struct FCurve *fcurve);
+void BKE_animsys_update_driver_array(struct ID *id);
/* ************************************* */
diff --git a/source/blender/blenkernel/BKE_appdir.h b/source/blender/blenkernel/BKE_appdir.h
index ac8f861fa56..6162c7b6bf6 100644
--- a/source/blender/blenkernel/BKE_appdir.h
+++ b/source/blender/blenkernel/BKE_appdir.h
@@ -23,6 +23,7 @@
/** \file BKE_appdir.h
* \ingroup bli
*/
+struct ListBase;
/* note on naming: typical _get() suffix is omitted here,
* since its the main purpose of the API. */
@@ -35,6 +36,7 @@ const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, con
bool BKE_appdir_app_template_any(void);
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_len);
+void BKE_appdir_app_templates(struct ListBase *templates);
/* Initialize path to program executable */
void BKE_appdir_program_path_init(const char *argv0);
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index dea5afa1ac2..23a9afbda31 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -33,7 +33,9 @@
* \author nzc
*/
+struct bPose;
struct Bone;
+struct Depsgraph;
struct GHash;
struct Main;
struct bArmature;
@@ -97,17 +99,19 @@ float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3
void BKE_armature_where_is(struct bArmature *arm);
void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion);
void BKE_pose_clear_pointers(struct bPose *pose);
-void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm);
-void BKE_pose_rebuild_ex(struct Object *ob, struct bArmature *arm, const bool sort_bones);
-void BKE_pose_where_is(struct Scene *scene, struct Object *ob);
-void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra);
+void BKE_pose_remap_bone_pointers(struct bArmature *armature, struct bPose *pose);
+void BKE_pchan_rebuild_bbone_handles(struct bPose *pose, struct bPoseChannel *pchan);
+void BKE_pose_rebuild(struct Main *bmain, struct Object *ob, struct bArmature *arm, const bool do_id_user);
+void BKE_pose_where_is(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+void BKE_pose_where_is_bone(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra);
void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
/* get_objectspace_bone_matrix has to be removed still */
void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], int root, int posed);
void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3]);
void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float mat[3][3]);
-void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll);
+void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll);
+void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll);
/* Common Conversions Between Co-ordinate Spaces */
void BKE_armature_mat_world_to_pose(struct Object *ob, float inmat[4][4], float outmat[4][4]);
@@ -117,7 +121,7 @@ void BKE_armature_loc_pose_to_bone(struct bPoseChannel *pchan, const float inloc
void BKE_armature_mat_bone_to_pose(struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]);
void BKE_armature_mat_pose_to_delta(float delta_mat[4][4], float pose_mat[4][4], float arm_mat[4][4]);
-void BKE_armature_mat_pose_to_bone_ex(struct Object *ob, struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]);
+void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, struct Object *ob, struct bPoseChannel *pchan, float inmat[4][4], float outmat[4][4]);
void BKE_pchan_mat3_to_rot(struct bPoseChannel *pchan, float mat[3][3], bool use_compat);
void BKE_pchan_apply_mat4(struct bPoseChannel *pchan, float mat[4][4], bool use_comat);
@@ -138,8 +142,33 @@ typedef struct Mat4 {
float mat[4][4];
} Mat4;
-void equalize_bbone_bezier(float *data, int desired);
-void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
+typedef struct BBoneSplineParameters {
+ int segments;
+ float length;
+
+ /* Non-uniform scale correction. */
+ bool do_scale;
+ float scale[3];
+
+ /* Handle control bone data. */
+ bool use_prev, prev_bbone;
+ bool use_next, next_bbone;
+
+ float prev_h[3], next_h[3];
+ float prev_mat[4][4], next_mat[4][4];
+
+ /* Control values. */
+ float ease1, ease2;
+ float roll1, roll2;
+ float scaleIn, scaleOut;
+ float curveInX, curveInY, curveOutX, curveOutY;
+} BBoneSplineParameters;
+
+void BKE_pchan_get_bbone_handles(struct bPoseChannel *pchan, struct bPoseChannel **r_prev, struct bPoseChannel **r_next);
+
+void b_bone_spline_setup(struct bPoseChannel *pchan, const bool rest, Mat4 result_array[MAX_BBONE_SUBDIV]);
+
+int BKE_compute_b_bone_spline(struct BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV]);
/* like EBONE_VISIBLE */
#define PBONE_VISIBLE(arm, bone) ( \
@@ -151,11 +180,27 @@ void b_bone_spline_setup(struct bPoseChannel *pchan, int rest, Mat4 result_array
#define PBONE_SELECTABLE(arm, bone) \
(PBONE_VISIBLE(arm, bone) && !((bone)->flag & BONE_UNSELECTABLE))
+
+/* context.selected_pose_bones */
+#define FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN(_ob, _pchan) \
+ for (bPoseChannel *_pchan = (_ob)->pose->chanbase.first; _pchan; _pchan = _pchan->next) { \
+ if (PBONE_VISIBLE(((bArmature *)(_ob)->data), (_pchan)->bone) && ((_pchan)->bone->flag & BONE_SELECTED)) {
+#define FOREACH_PCHAN_SELECTED_IN_OBJECT_END \
+ } \
+ } ((void)0)
+/* context.visible_pose_bones */
+#define FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN(_ob, _pchan) \
+ for (bPoseChannel *_pchan = (_ob)->pose->chanbase.first; _pchan; _pchan = _pchan->next) { \
+ if (PBONE_VISIBLE(((bArmature *)(_ob)->data), (_pchan)->bone)) {
+#define FOREACH_PCHAN_VISIBLE_IN_OBJECT_END \
+ } \
+ } ((void)0)
+
+
/* Evaluation helpers */
struct bKinematicConstraint;
struct bPose;
struct bSplineIKConstraint;
-struct EvaluationContext;
struct bPoseChannel *BKE_armature_ik_solver_find_root(
struct bPoseChannel *pchan,
@@ -165,46 +210,63 @@ struct bPoseChannel *BKE_armature_splineik_solver_find_root(
struct bSplineIKConstraint *data);
void BKE_pose_splineik_init_tree(struct Scene *scene, struct Object *ob, float ctime);
-void BKE_splineik_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
-
-void BKE_pose_eval_init(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
-
-void BKE_pose_eval_init_ik(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
-
-void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- int pchan_index);
-
-void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- int pchan_index);
-
-void BKE_pose_bone_done(struct EvaluationContext *eval_ctx,
- struct Object *ob,
- int pchan_index);
-
-void BKE_pose_iktree_evaluate(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- int rootchan_index);
-
-void BKE_pose_splineik_evaluate(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob,
- int rootchan_index);
-
-void BKE_pose_eval_flush(struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
-
-void BKE_pose_eval_proxy_copy(struct EvaluationContext *eval_ctx,
- struct Object *ob);
+void BKE_splineik_execute_tree(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, struct bPoseChannel *pchan_root, float ctime);
+
+void BKE_pose_eval_init(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
+
+void BKE_pose_eval_init_ik(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
+
+void BKE_pose_eval_bone(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ int pchan_index);
+
+void BKE_pose_constraints_evaluate(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ int pchan_index);
+
+void BKE_pose_bone_done(
+ struct Depsgraph *depsgraph,
+ struct Object *ob,
+ int pchan_index);
+
+void BKE_pose_iktree_evaluate(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ int rootchan_index);
+
+void BKE_pose_splineik_evaluate(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob,
+ int rootchan_index);
+
+void BKE_pose_eval_cleanup(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
+
+void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph,
+ struct Object *object);
+void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph,
+ struct Object *object);
+
+void BKE_pose_eval_proxy_copy_bone(
+ struct Depsgraph *depsgraph,
+ struct Object *object,
+ int pchan_index);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_blender_user_menu.h b/source/blender/blenkernel/BKE_blender_user_menu.h
new file mode 100644
index 00000000000..ff314314646
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blender_user_menu.h
@@ -0,0 +1,49 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_BLENDER_USER_MENU_H__
+#define __BKE_BLENDER_USER_MENU_H__
+
+/** \file BKE_blender_user_menu.h
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ListBase;
+struct bUserMenu;
+struct bUserMenuItem;
+
+struct bUserMenu *BKE_blender_user_menu_find(
+ struct ListBase *lb, char space_type, const char *context);
+struct bUserMenu *BKE_blender_user_menu_ensure(
+ struct ListBase *lb, char space_type, const char *context);
+
+struct bUserMenuItem *BKE_blender_user_menu_item_add(struct ListBase *lb, int type);
+void BKE_blender_user_menu_item_free(struct bUserMenuItem *umi);
+void BKE_blender_user_menu_item_free_list(struct ListBase *lb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_BLENDER_USER_MENU_H__ */
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 16115203294..b695132416e 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,11 +27,11 @@
/* these lines are grep'd, watch out for our not-so-awesome regex
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
-#define BLENDER_VERSION 279
-#define BLENDER_SUBVERSION 6
-/* Several breakages with 270, e.g. constraint deg vs rad */
-#define BLENDER_MINVERSION 270
-#define BLENDER_MINSUBVERSION 6
+#define BLENDER_VERSION 280
+#define BLENDER_SUBVERSION 30
+/* Several breakages with 280, e.g. collections vs layers */
+#define BLENDER_MINVERSION 280
+#define BLENDER_MINSUBVERSION 0
/* used by packaging tools */
/* can be left blank, otherwise a,b,c... etc with no quotes */
diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h
index 9ff164f60be..305b7d07e4d 100644
--- a/source/blender/blenkernel/BKE_blendfile.h
+++ b/source/blender/blenkernel/BKE_blendfile.h
@@ -61,6 +61,13 @@ struct UserDef *BKE_blendfile_userdef_read_from_memory(
bool BKE_blendfile_userdef_write(const char *filepath, struct ReportList *reports);
bool BKE_blendfile_userdef_write_app_template(const char *filepath, struct ReportList *reports);
+struct WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(
+ const char *filepath,
+ const void *filebuf, int filelength,
+ struct ReportList *reports);
+bool BKE_blendfile_workspace_config_write(struct Main *bmain, const char *filepath, struct ReportList *reports);
+void BKE_blendfile_workspace_config_data_free(struct WorkspaceConfigFileData *workspace_config);
+
/* partial blend file writing */
void BKE_blendfile_write_partial_tag_ID(struct ID *id, bool set);
void BKE_blendfile_write_partial_begin(struct Main *bmain_src);
diff --git a/source/blender/blenkernel/BKE_bmfont.h b/source/blender/blenkernel/BKE_bmfont.h
deleted file mode 100644
index 3be84c83892..00000000000
--- a/source/blender/blenkernel/BKE_bmfont.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_BMFONT_H__
-#define __BKE_BMFONT_H__
-
-/** \file BKE_bmfont.h
- * \ingroup bke
- * \since March 2001
- * \author nzc
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct bmGlyph;
-struct ImBuf;
-struct bmFont;
-
-void printfGlyph(struct bmGlyph *glyph);
-void calcAlpha(struct ImBuf *ibuf);
-void readBitmapFontVersion0(struct ImBuf *ibuf,
- unsigned char *rect,
- int step);
-void detectBitmapFont(struct ImBuf *ibuf);
-int locateGlyph(struct bmFont *bmfont, unsigned short unicode);
-void matrixGlyph(struct ImBuf *ibuf, unsigned short unicode,
- float *centerx, float *centery,
- float *sizex, float *sizey,
- float *transx, float *transy,
- float *movex, float *movey, float *advance);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 9fc399c428f..91743bfa567 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -28,12 +28,17 @@
*/
enum eCurveMappingPreset;
+struct bContext;
struct Brush;
+struct Paint;
struct ImBuf;
struct ImagePool;
struct Main;
struct Scene;
+struct ToolSettings;
struct UnifiedPaintSettings;
+struct Material;
+
// enum eCurveMappingPreset;
#include "DNA_object_enums.h"
@@ -45,14 +50,17 @@ void BKE_brush_system_exit(void);
/* datablock functions */
void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode);
+struct Brush *BKE_brush_add_gpencil(struct Main *bmain, struct ToolSettings *ts, const char *name);
+void BKE_brush_init_gpencil_settings(struct Brush *brush);
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode);
void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag);
struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush);
void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local);
-void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
+void BKE_brush_gpencil_presets(struct bContext *C);
+void BKE_brush_update_material(struct Main *bmain, struct Material *ma, struct Brush *exclude_brush);
/* image icon function */
struct ImBuf *get_brush_icon(struct Brush *brush);
@@ -117,6 +125,14 @@ void BKE_brush_scale_size(
float new_unprojected_radius,
float old_unprojected_radius);
+/* Accessors */
+#define BKE_brush_tool_get(brush, p) \
+ (CHECK_TYPE_ANY(brush, struct Brush *, const struct Brush *), \
+ *(const char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset))
+#define BKE_brush_tool_set(brush, p, tool) { \
+ CHECK_TYPE_ANY(brush, struct Brush *); \
+ *(char *)POINTER_OFFSET(brush, (p)->runtime.tool_offset) = tool; } ((void)0)
+
/* debugging only */
void BKE_brush_debug_print_state(struct Brush *br);
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index c6057442fec..018f535a4cb 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -40,6 +40,7 @@
struct DerivedMesh;
struct BMEditMesh;
+struct Mesh;
struct MVert;
struct MFace;
@@ -101,7 +102,7 @@ typedef struct BVHTreeFromMesh {
*/
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
- float epsilon, int tree_type, int axis);
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache);
BVHTree *bvhtree_from_editmesh_verts_ex(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
const BLI_bitmap *mask, int verts_num_active,
@@ -114,7 +115,7 @@ BVHTree *bvhtree_from_mesh_verts_ex(
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
- float epsilon, int tree_type, int axis);
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache);
BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTreeFromEditMesh *data, struct BMEditMesh *em,
const BLI_bitmap *edges_mask, int edges_num_active,
@@ -150,8 +151,8 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
const BLI_bitmap *mask, int looptri_num_active,
float epsilon, int tree_type, int axis);
-BVHTree *bvhtree_from_mesh_get(
- struct BVHTreeFromMesh *data, struct DerivedMesh *mesh,
+BVHTree *BKE_bvhtree_from_mesh_get(
+ struct BVHTreeFromMesh *data, struct Mesh *mesh,
const int type, const int tree_type);
/**
@@ -182,14 +183,18 @@ enum {
BVHTREE_FROM_FACES = 2,
BVHTREE_FROM_LOOPTRI = 3,
- BVHTREE_FROM_EM_LOOPTRI = 4,
+ BVHTREE_FROM_LOOSEVERTS = 4,
+ BVHTREE_FROM_LOOSEEDGES = 5,
+
+ BVHTREE_FROM_EM_VERTS = 6,
+ BVHTREE_FROM_EM_EDGES = 7,
+ BVHTREE_FROM_EM_LOOPTRI = 8,
};
-BVHTree *bvhcache_find(BVHCache *cache, int type);
+bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree);
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree);
void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type);
-void bvhcache_init(BVHCache **cache_p);
void bvhcache_free(BVHCache **cache_p);
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
index e9712681090..43768b67f8f 100644
--- a/source/blender/blenkernel/BKE_cachefile.h
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -35,6 +35,7 @@ extern "C" {
#endif
struct CacheFile;
+struct Depsgraph;
struct Main;
struct Scene;
@@ -57,7 +58,7 @@ void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file
void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
-void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene, const float ctime, const float fps);
+void BKE_cachefile_update_frame(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, const float ctime, const float fps);
bool BKE_cachefile_filepath_get(
const struct Main *bmain, const struct CacheFile *cache_file, float frame,
@@ -65,7 +66,7 @@ bool BKE_cachefile_filepath_get(
float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
-void BKE_cachefile_clean(struct Scene *scene, struct CacheFile *cache_file);
+void BKE_cachefile_clean(struct Main *bmain, struct CacheFile *cache_file);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 8eb8ef22b49..d8e2139be83 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -39,11 +39,13 @@ extern "C" {
#include "DNA_vec_types.h"
struct Camera;
+struct Depsgraph;
struct Main;
struct Object;
struct RegionView3D;
struct RenderData;
struct Scene;
+struct ViewLayer;
struct rctf;
struct View3D;
struct GPUFXSettings;
@@ -60,7 +62,6 @@ void BKE_camera_free(struct Camera *ca);
/* Camera Usage */
float BKE_camera_object_dof_distance(struct Object *ob);
-void BKE_camera_object_mode(struct RenderData *rd, struct Object *ob);
int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey);
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y);
@@ -91,11 +92,6 @@ typedef struct CameraParams {
float clipsta;
float clipend;
- /* fields */
- int use_fields;
- int field_second;
- int field_odd;
-
/* computed viewplane */
float ycor;
float viewdx;
@@ -112,7 +108,7 @@ typedef struct CameraParams {
void BKE_camera_params_init(CameraParams *params);
void BKE_camera_params_from_object(CameraParams *params, const struct Object *camera);
-void BKE_camera_params_from_view3d(CameraParams *params, const struct View3D *v3d, const struct RegionView3D *rv3d);
+void BKE_camera_params_from_view3d(CameraParams *params, struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d);
void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int winy, float aspx, float aspy);
void BKE_camera_params_compute_matrix(CameraParams *params);
@@ -128,12 +124,13 @@ void BKE_camera_view_frame(
float r_vec[4][3]);
bool BKE_camera_view_frame_fit_to_scene(
- struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct Object *camera_ob,
+ struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *camera_ob,
float r_co[3], float *r_scale);
bool BKE_camera_view_frame_fit_to_coords(
- const struct Scene *scene,
+ const struct Depsgraph *depsgraph,
const float (*cos)[3], int num_cos,
- const struct Object *camera_ob,
+ struct Object *camera_ob,
float r_co[3], float *r_scale);
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings);
@@ -141,11 +138,16 @@ void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_set
/* Camera multi-view API */
struct Object *BKE_camera_multiview_render(struct Scene *scene, struct Object *camera, const char *viewname);
-void BKE_camera_multiview_view_matrix(struct RenderData *rd, struct Object *camera, const bool is_left, float r_viewmat[4][4]);
-void BKE_camera_multiview_model_matrix(struct RenderData *rd, struct Object *camera, const char *viewname, float r_modelmat[4][4]);
-float BKE_camera_multiview_shift_x(struct RenderData *rd, struct Object *camera, const char *viewname);
-void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, struct Object *camera, const char *viewname);
-bool BKE_camera_multiview_spherical_stereo(struct RenderData *rd, struct Object *camera);
+void BKE_camera_multiview_view_matrix(struct RenderData *rd, const struct Object *camera, const bool is_left, float r_viewmat[4][4]);
+void BKE_camera_multiview_model_matrix(struct RenderData *rd, const struct Object *camera, const char *viewname, float r_modelmat[4][4]);
+float BKE_camera_multiview_shift_x(struct RenderData *rd, const struct Object *camera, const char *viewname);
+void BKE_camera_multiview_params(struct RenderData *rd, struct CameraParams *params, const struct Object *camera, const char *viewname);
+bool BKE_camera_multiview_spherical_stereo(struct RenderData *rd, const struct Object *camera);
+
+/* Camera background image API */
+struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam);
+void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic);
+void BKE_camera_background_image_clear(struct Camera *cam);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index 761b679983d..f2c0b96aa80 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -36,6 +36,7 @@
#define __BKE_CDDERIVEDMESH_H__
#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
struct DerivedMesh;
struct BMEditMesh;
@@ -53,20 +54,15 @@ struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces,
* data to not overwrite the original */
struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh);
+/* creates a CDDerivedMesh from the given Mesh with custom allocation type. */
+struct DerivedMesh *CDDM_from_mesh_ex(struct Mesh *mesh, eCDAllocType alloctype, CustomDataMask mask);
+
+
struct DerivedMesh *CDDM_from_bmesh(struct BMesh *bm, const bool use_mdisps);
/* creates a CDDerivedMesh from the given BMEditMesh */
DerivedMesh *CDDM_from_editbmesh(struct BMEditMesh *em, const bool use_mdisps, const bool use_tessface);
-/* merge verts */
-/* Enum for merge_mode of CDDM_merge_verts.
- * Refer to cdderivedmesh.c for details. */
-enum {
- CDDM_MERGE_VERTS_DUMP_IF_MAPPED,
- CDDM_MERGE_VERTS_DUMP_IF_EQUAL,
-};
-DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode);
-
/* creates a CDDerivedMesh from the given curve object */
struct DerivedMesh *CDDM_from_curve(struct Object *ob);
@@ -78,8 +74,6 @@ DerivedMesh *CDDM_from_curve_displist(struct Object *ob, struct ListBase *dispba
* custom element data.
*/
struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);
-struct DerivedMesh *CDDM_copy_from_tessface(struct DerivedMesh *dm);
-struct DerivedMesh *CDDM_copy_with_tessface(struct DerivedMesh *dm);
/* creates a CDDerivedMesh with the same layer stack configuration as the
* given DerivedMesh and containing the requested numbers of elements.
@@ -95,11 +89,6 @@ struct DerivedMesh *CDDM_from_template(
int numVerts, int numEdges, int numFaces,
int numLoops, int numPolys);
-/* converts mfaces to mpolys. note things may break if there are not valid
- * medges surrounding each mface.
- */
-void CDDM_tessfaces_to_faces(struct DerivedMesh *dm);
-
/* applies vertex coordinates or normals to a CDDerivedMesh. if the MVert
* layer is a referenced layer, it will be duplicate to not overwrite the
* original
@@ -112,22 +101,11 @@ void CDDM_apply_vert_normals(struct DerivedMesh *cddm, short (*vertNormals)[3]);
void CDDM_calc_normals_mapping_ex(struct DerivedMesh *dm, const bool only_face_normals);
void CDDM_calc_normals_mapping(struct DerivedMesh *dm);
void CDDM_calc_normals(struct DerivedMesh *dm);
-void CDDM_calc_normals_tessface(struct DerivedMesh *dm);
void CDDM_calc_loop_normals(struct DerivedMesh *dm, const bool use_split_normals, const float split_angle);
void CDDM_calc_loop_normals_spacearr(struct DerivedMesh *dm, const bool use_split_normals, const float split_angle,
struct MLoopNorSpaceArray *r_lnors_spacearr);
-/* calculates edges for a CDDerivedMesh (from face data)
- * this completely replaces the current edge data in the DerivedMesh
- * builds edges from the tessellated face data.
- */
-void CDDM_calc_edges_tessface(struct DerivedMesh *dm);
-
-/* same as CDDM_calc_edges_tessface only makes edges from ngon faces instead of tessellation
- * faces*/
-void CDDM_calc_edges(struct DerivedMesh *dm);
-
/* reconstitute face triangulation */
void CDDM_recalc_tessellation(struct DerivedMesh *dm);
void CDDM_recalc_tessellation_ex(struct DerivedMesh *dm, const bool do_face_nor_cpy);
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 6b76ec33c06..87094e77953 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -37,10 +37,11 @@
struct Object;
struct Scene;
+struct Mesh;
struct MFace;
-struct DerivedMesh;
struct ClothModifierData;
struct CollisionModifierData;
+struct Depsgraph;
#define DO_INLINE MALWAYS_INLINE
@@ -116,6 +117,7 @@ typedef struct ClothVertex {
float goal; /* goal, from SB */
float impulse[3]; /* used in collision.c */
float xrest[3]; /* rest position of the vertex */
+ float dcvel[3]; /* delta velocities to be applied by collision response */
unsigned int impulse_count; /* same as above */
float avg_spring_len; /* average length of connected springs */
float struct_stiff;
@@ -132,11 +134,17 @@ ClothVertex;
typedef struct ClothSpring {
int ij; /* Pij from the paper, one end of the spring. */
int kl; /* Pkl from the paper, one end of the spring. */
- int mn;
- float restlen; /* The original length of the spring. */
- int type; /* types defined in BKE_cloth.h ("springType") */
- int flags; /* defined in BKE_cloth.h, e.g. deactivated due to tearing */
- float stiffness; /* stiffness factor from the vertex groups */
+ int mn; /* For hair springs: third vertex index; For bending springs: edge index; */
+ int *pa; /* Array of vert indices for poly a (for bending springs). */
+ int *pb; /* Array of vert indices for poly b (for bending springs). */
+ int la; /* Length of *pa. */
+ int lb; /* Length of *pb. */
+ float restlen; /* The original length of the spring. */
+ float restang; /* The original angle of the bending springs. */
+ int type; /* Types defined in BKE_cloth.h ("springType"). */
+ int flags; /* Defined in BKE_cloth.h, e.g. deactivated due to tearing. */
+ float lin_stiffness; /* Linear stiffness factor from the vertex groups. */
+ float ang_stiffness; /* Angular stiffness factor from the vertex groups. */
float editrestlen;
/* angular bending spring target and derivatives */
@@ -162,15 +170,21 @@ ClothSpring;
/* These are the bits used in SimSettings.flags. */
typedef enum {
CLOTH_SIMSETTINGS_FLAG_COLLOBJ = ( 1 << 2 ),// object is only collision object, no cloth simulation is done
- CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), // we have goals enabled
+ CLOTH_SIMSETTINGS_FLAG_GOAL = ( 1 << 3 ), /* DEPRECATED, for versioning only. */
CLOTH_SIMSETTINGS_FLAG_TEARING = ( 1 << 4 ),// true if tearing is enabled
- CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* is advanced scaling active? */
+ CLOTH_SIMSETTINGS_FLAG_SCALING = ( 1 << 8 ), /* DEPRECATED, for versioning only. */
CLOTH_SIMSETTINGS_FLAG_CCACHE_EDIT = (1 << 12), /* edit cache in editmode */
- CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS = (1 << 13), /* don't allow spring compression */
+ CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS = (1 << 13), /* don't allow spring compression */
CLOTH_SIMSETTINGS_FLAG_SEW = (1 << 14), /* pull ends of loose edges together */
CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH = (1 << 15), /* make simulation respect deformations in the base object */
} CLOTH_SIMSETTINGS_FLAGS;
+/* ClothSimSettings.bending_model. */
+typedef enum {
+ CLOTH_BENDING_LINEAR = 0,
+ CLOTH_BENDING_ANGULAR = 1,
+} CLOTH_BENDING_MODEL;
+
/* COLLISION FLAGS */
typedef enum {
CLOTH_COLLSETTINGS_FLAG_ENABLED = ( 1 << 1 ), /* enables cloth - object collisions */
@@ -179,12 +193,12 @@ typedef enum {
/* Spring types as defined in the paper.*/
typedef enum {
- CLOTH_SPRING_TYPE_STRUCTURAL = (1 << 1),
- CLOTH_SPRING_TYPE_SHEAR = (1 << 2),
- CLOTH_SPRING_TYPE_BENDING = (1 << 3),
- CLOTH_SPRING_TYPE_GOAL = (1 << 4),
- CLOTH_SPRING_TYPE_SEWING = (1 << 5),
- CLOTH_SPRING_TYPE_BENDING_ANG = (1 << 6),
+ CLOTH_SPRING_TYPE_STRUCTURAL = (1 << 1),
+ CLOTH_SPRING_TYPE_SHEAR = (1 << 2),
+ CLOTH_SPRING_TYPE_BENDING = (1 << 3),
+ CLOTH_SPRING_TYPE_GOAL = (1 << 4),
+ CLOTH_SPRING_TYPE_SEWING = (1 << 5),
+ CLOTH_SPRING_TYPE_BENDING_HAIR = (1 << 6),
} CLOTH_SPRING_TYPES;
/* SPRING FLAGS */
@@ -209,10 +223,9 @@ typedef struct ColliderContacts {
} ColliderContacts;
// needed for implicit.c
-int cloth_bvh_objcollision (struct Object *ob, struct ClothModifierData *clmd, float step, float dt );
-int cloth_points_objcollision(struct Object *ob, struct ClothModifierData *clmd, float step, float dt);
+int cloth_bvh_collision(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt);
-void cloth_find_point_contacts(struct Object *ob, struct ClothModifierData *clmd, float step, float dt,
+void cloth_find_point_contacts(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt,
ColliderContacts **r_collider_contacts, int *r_totcolliders);
void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders);
@@ -226,16 +239,18 @@ void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders);
void cloth_free_modifier_extern (struct ClothModifierData *clmd );
void cloth_free_modifier (struct ClothModifierData *clmd );
void cloth_init (struct ClothModifierData *clmd );
-void clothModifier_do (struct ClothModifierData *clmd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3]);
+void clothModifier_do(
+ struct ClothModifierData *clmd, struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, struct Mesh *me, float (*vertexCos)[3]);
int cloth_uses_vgroup(struct ClothModifierData *clmd);
// needed for collision.c
-void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
-void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
+void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving, bool self);
// needed for button_object.c
-void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float framenr );
+void cloth_clear_cache(
+ struct Object *ob, struct ClothModifierData *clmd, float framenr );
void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3]);
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
new file mode 100644
index 00000000000..a9539b3a3c4
--- /dev/null
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -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.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_COLLECTION_H__
+#define __BKE_COLLECTION_H__
+
+/** \file blender/blenkernel/BKE_collection.h
+ * \ingroup bke
+ */
+
+#include "BLI_compiler_compat.h"
+#include "BLI_ghash.h"
+#include "BLI_iterator.h"
+#include "DNA_listBase.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Structs */
+
+struct Base;
+struct BLI_Iterator;
+struct Collection;
+struct Depsgraph;
+struct ID;
+struct Main;
+struct Object;
+struct Scene;
+struct ViewLayer;
+
+typedef struct CollectionParent {
+ struct CollectionParent *next, *prev;
+ struct Collection *collection;
+} CollectionParent;
+
+/* Collections */
+
+struct Collection *BKE_collection_add(struct Main *bmain, struct Collection *parent, const char *name);
+void BKE_collection_free(struct Collection *collection);
+bool BKE_collection_delete(struct Main *bmain, struct Collection *collection, bool hierarchy);
+
+struct Collection *BKE_collection_copy(struct Main *bmain, struct Collection *parent, struct Collection *collection);
+struct Collection *BKE_collection_copy_master(struct Main *bmain, struct Collection *collection, const int flag);
+void BKE_collection_copy_data(struct Main *bmain, struct Collection *collection_dst, const struct Collection *collection_src, const int flag);
+void BKE_collection_copy_full(struct Main *bmain, struct Collection *collection);
+void BKE_collection_make_local(struct Main *bmain, struct Collection *collection, const bool lib_local);
+
+/* Master Collection for Scene */
+
+struct Collection *BKE_collection_master(const struct Scene *scene);
+struct Collection *BKE_collection_master_add(void);
+
+/* Collection Objects */
+
+bool BKE_collection_has_object(struct Collection *collection, struct Object *ob);
+bool BKE_collection_has_object_recursive(struct Collection *collection, struct Object *ob);
+struct Collection *BKE_collection_object_find(struct Main *bmain, struct Collection *collection, struct Object *ob);
+bool BKE_collection_is_empty(struct Collection *collection);
+
+bool BKE_collection_object_add(struct Main *bmain, struct Collection *collection, struct Object *ob);
+void BKE_collection_object_add_from(struct Main *bmain, struct Scene *scene, struct Object *ob_src, struct Object *ob_dst);
+bool BKE_collection_object_remove(struct Main *bmain, struct Collection *collection, struct Object *object, const bool free_us);
+void BKE_collection_object_move(struct Main *bmain, struct Scene *scene, struct Collection *collection_dst, struct Collection *collection_src, struct Object *ob);
+
+bool BKE_scene_collections_object_remove(struct Main *bmain, struct Scene *scene, struct Object *object, const bool free_us);
+void BKE_collections_object_remove_nulls(struct Main *bmain);
+void BKE_collections_child_remove_nulls(struct Main *bmain, struct Collection *old_collection);
+
+/* Dependencies. */
+
+bool BKE_collection_is_in_scene(struct Collection *collection);
+void BKE_collections_after_lib_link(struct Main *bmain);
+bool BKE_collection_object_cyclic_check(struct Main *bmain, struct Object *object, struct Collection *collection);
+
+/* Object list cache. */
+
+struct ListBase BKE_collection_object_cache_get(struct Collection *collection);
+void BKE_collection_object_cache_free(struct Collection *collection);
+
+struct Base *BKE_collection_or_layer_objects(const struct ViewLayer *view_layer, struct Collection *collection);
+
+/* Editing. */
+
+struct Collection *BKE_collection_from_index(struct Scene *scene, const int index);
+void BKE_collection_new_name_get(struct Collection *collection_parent, char *rname);
+bool BKE_collection_objects_select(struct ViewLayer *view_layer, struct Collection *collection, bool deselect);
+
+/* Collection children */
+
+bool BKE_collection_child_add(struct Main *bmain,
+ struct Collection *parent,
+ struct Collection *child);
+
+bool BKE_collection_child_remove(struct Main *bmain,
+ struct Collection *parent,
+ struct Collection *child);
+
+bool BKE_collection_move(struct Main *bmain,
+ struct Collection *to_parent,
+ struct Collection *from_parent,
+ struct Collection *relative,
+ bool relative_after,
+ struct Collection *collection);
+
+bool BKE_collection_find_cycle(struct Collection *new_ancestor,
+ struct Collection *collection);
+
+
+/* Iteration callbacks. */
+
+typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data);
+typedef void (*BKE_scene_collections_Cb)(struct Collection *ob, void *data);
+
+void BKE_scene_collections_callback(struct Scene *scene, BKE_scene_collections_Cb callback, void *data);
+void BKE_scene_objects_callback(struct Scene *scene, BKE_scene_objects_Cb callback, void *data);
+
+/* Iteratorion over objects in collection. */
+
+#define FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(_collection, _object, _mode) \
+ { \
+ int _base_flag = (_mode == DAG_EVAL_VIEWPORT) ? \
+ BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER; \
+ int _base_id = 0; \
+ for (Base *_base = (Base*)BKE_collection_object_cache_get(_collection).first; \
+ _base; \
+ _base = _base->next, _base_id++) \
+ { \
+ if (_base->flag & _base_flag) { \
+ Object *_object = _base->object; \
+
+#define FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END \
+ } \
+ } \
+ }
+
+#define FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(_collection, _object) \
+ for (Base *_base = (Base*)BKE_collection_object_cache_get(_collection).first; \
+ _base; \
+ _base = _base->next) \
+ { \
+ Object *_object = _base->object; \
+ BLI_assert(_object != NULL);
+
+#define FOREACH_COLLECTION_OBJECT_RECURSIVE_END \
+ } ((void)0)
+
+/* Iteration over collections in scene. */
+
+void BKE_scene_collections_iterator_begin(struct BLI_Iterator *iter, void *data_in);
+void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter);
+void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter);
+
+void BKE_scene_objects_iterator_begin(struct BLI_Iterator *iter, void *data_in);
+void BKE_scene_objects_iterator_next(struct BLI_Iterator *iter);
+void BKE_scene_objects_iterator_end(struct BLI_Iterator *iter);
+
+#define FOREACH_SCENE_COLLECTION_BEGIN(scene, _instance) \
+ ITER_BEGIN(BKE_scene_collections_iterator_begin, \
+ BKE_scene_collections_iterator_next, \
+ BKE_scene_collections_iterator_end, \
+ scene, Collection *, _instance)
+
+#define FOREACH_SCENE_COLLECTION_END \
+ ITER_END
+
+#define FOREACH_SCENE_OBJECT_BEGIN(scene, _instance) \
+ ITER_BEGIN(BKE_scene_objects_iterator_begin, \
+ BKE_scene_objects_iterator_next, \
+ BKE_scene_objects_iterator_end, \
+ scene, Object *, _instance)
+
+#define FOREACH_SCENE_OBJECT_END \
+ ITER_END
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_COLLECTION_H__ */
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index 98dc7d69c0d..9bd1f5385da 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -44,11 +44,12 @@
#include "BLI_kdopbvh.h"
struct CollisionModifierData;
-struct Group;
+struct Collection;
struct MFace;
struct MVert;
struct Object;
struct Scene;
+struct Depsgraph;
struct MVertTri;
////////////////////////////////////////
@@ -62,6 +63,7 @@ typedef enum {
COLLISION_USE_COLLFACE = (1 << 2),
COLLISION_IS_EDGES = (1 << 3),
#endif
+ COLLISION_INACTIVE = (1 << 4),
} COLLISION_FLAGS;
@@ -72,7 +74,7 @@ typedef enum {
typedef struct CollPair {
unsigned int face1; // cloth face
unsigned int face2; // object face
- double distance; // magnitude of vector
+ float distance;
float normal[3];
float vector[3]; // unnormalized collision vector: p2-p1
float pa[3], pb[3]; // collision point p1 on face1, p2 on face2
@@ -143,14 +145,29 @@ void collision_move_object(struct CollisionModifierData *collmd, float step, flo
void collision_get_collider_velocity(float vel_old[3], float vel_new[3], struct CollisionModifierData *collmd, struct CollPair *collpair);
-/////////////////////////////////////////////////
-// used in effect.c
-/////////////////////////////////////////////////
-/* explicit control over layer mask and dupli recursion */
-struct Object **get_collisionobjects_ext(struct Scene *scene, struct Object *self, struct Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli);
+/* Collision relations for dependency graph build. */
+
+typedef struct CollisionRelation {
+ struct CollisionRelation *next, *prev;
+ struct Object *ob;
+} CollisionRelation;
+
+struct ListBase *BKE_collision_relations_create(
+ struct Depsgraph *depsgraph,
+ struct Collection *collection,
+ unsigned int modifier_type);
+void BKE_collision_relations_free(struct ListBase *relations);
+
+/* Collision object lists for physics simulation evaluation. */
-struct Object **get_collisionobjects(struct Scene *scene, struct Object *self, struct Group *group, unsigned int *numcollobj, unsigned int modifier_type);
+struct Object **BKE_collision_objects_create(
+ struct Depsgraph *depsgraph,
+ struct Object *self,
+ struct Collection *collection,
+ unsigned int *numcollobj,
+ unsigned int modifier_type);
+void BKE_collision_objects_free(struct Object **objects);
typedef struct ColliderCache {
struct ColliderCache *next, *prev;
@@ -158,8 +175,11 @@ typedef struct ColliderCache {
struct CollisionModifierData *collmd;
} ColliderCache;
-struct ListBase *get_collider_cache(struct Scene *scene, struct Object *self, struct Group *group);
-void free_collider_cache(struct ListBase **colliders);
+struct ListBase *BKE_collider_cache_create(
+ struct Depsgraph *scene,
+ struct Object *self,
+ struct Collection *collection);
+void BKE_collider_cache_free(struct ListBase **colliders);
/////////////////////////////////////////////////
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index 293ac30f0f9..e7672001a15 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -40,6 +40,7 @@ struct ListBase;
struct Object;
struct Scene;
struct bPoseChannel;
+struct Depsgraph;
/* ---------------------------------------------------------------------------- */
#ifdef __cplusplus
@@ -48,6 +49,7 @@ extern "C" {
/* special struct for use in constraint evaluation */
typedef struct bConstraintOb {
+ struct Depsgraph *depsgraph;/* to get evaluated armature. */
struct Scene *scene; /* for system time, part of deglobalization, code nicer later with local time (ton) */
struct Object *ob; /* if pchan, then armature that it comes from, otherwise constraint owner */
struct bPoseChannel *pchan; /* pose channel that owns the constraints being evaluated */
@@ -104,7 +106,7 @@ typedef struct bConstraintTypeInfo {
/* evaluation */
/* set the ct->matrix for the given constraint target (at the given ctime) */
- void (*get_target_matrix)(struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime);
+ void (*get_target_matrix)(struct Depsgraph *depsgraph, struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime);
/* evaluate the constraint for the given time */
void (*evaluate_constraint)(struct bConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
} bConstraintTypeInfo;
@@ -119,6 +121,8 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
/* Constraint function prototypes */
void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list);
+struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src, const int flag, const bool do_extern);
+
void BKE_constraints_free(struct ListBase *list);
void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user);
void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern);
@@ -127,11 +131,15 @@ void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void
void BKE_constraint_free_data(struct bConstraint *con);
void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user);
+bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *ct);
+
/* Constraint API function prototypes */
struct bConstraint *BKE_constraints_active_get(struct ListBase *list);
void BKE_constraints_active_set(ListBase *list, struct bConstraint *con);
struct bConstraint *BKE_constraints_find_name(struct ListBase *list, const char *name);
+struct bConstraint *BKE_constraint_find_from_target(struct Object *ob, struct bConstraintTarget *tgt);
+
struct bConstraint *BKE_constraint_add_for_object(struct Object *ob, const char *name, short type);
struct bConstraint *BKE_constraint_add_for_pose(struct Object *ob, struct bPoseChannel *pchan, const char *name, short type);
@@ -143,15 +151,16 @@ void BKE_constraints_proxylocal_extract(struct ListBase *dst, struct ListBase *s
bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *pchan);
/* Constraint Evaluation function prototypes */
-struct bConstraintOb *BKE_constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype);
+struct bConstraintOb *BKE_constraints_make_evalob(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, void *subdata, short datatype);
void BKE_constraints_clear_evalob(struct bConstraintOb *cob);
void BKE_constraint_mat_convertspace(
struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale);
-void BKE_constraint_target_matrix_get(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime);
-void BKE_constraint_targets_for_solving_get(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime);
-void BKE_constraints_solve(struct ListBase *conlist, struct bConstraintOb *cob, float ctime);
+void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, struct Scene *scene, struct bConstraint *con,
+ int n, short ownertype, void *ownerdata, float mat[4][4], float ctime);
+void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime);
+void BKE_constraints_solve(struct Depsgraph *depsgraph, struct ListBase *conlist, struct bConstraintOb *cob, float ctime);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 4db365b7307..9379853af29 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -40,15 +40,21 @@ extern "C" {
struct ARegion;
struct bScreen;
struct CacheFile;
+struct Collection;
+struct Depsgraph;
+struct LayerCollection;
struct ListBase;
struct Main;
struct Object;
+struct Base;
struct PointerRNA;
struct ReportList;
struct Scene;
+struct ViewLayer;
struct ScrArea;
struct SpaceLink;
struct View3D;
+struct ViewRender;
struct RegionView3D;
struct StructRNA;
struct ToolSettings;
@@ -59,16 +65,17 @@ struct bPoseChannel;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
-struct bGPDpalette;
-struct bGPDpalettecolor;
-struct bGPDbrush;
+struct Brush;
struct wmWindow;
struct wmWindowManager;
+struct RenderEngineType;
struct SpaceText;
struct SpaceImage;
struct SpaceClip;
struct ID;
+#include "DNA_object_enums.h"
+
/* Structs */
struct bContext;
@@ -110,7 +117,12 @@ enum {
CTX_MODE_PAINT_VERTEX,
CTX_MODE_PAINT_TEXTURE,
CTX_MODE_PARTICLE,
- CTX_MODE_OBJECT
+ CTX_MODE_OBJECT,
+ CTX_MODE_GPENCIL_PAINT,
+ CTX_MODE_GPENCIL_EDIT,
+ CTX_MODE_GPENCIL_SCULPT,
+ CTX_MODE_GPENCIL_WEIGHT,
+ CTX_MODE_NUM /* must be last */
};
/* Context */
@@ -140,12 +152,15 @@ void CTX_py_dict_set(bContext *C, void *value);
struct wmWindowManager *CTX_wm_manager(const bContext *C);
struct wmWindow *CTX_wm_window(const bContext *C);
+struct WorkSpace *CTX_wm_workspace(const bContext *C);
struct bScreen *CTX_wm_screen(const bContext *C);
struct ScrArea *CTX_wm_area(const bContext *C);
struct SpaceLink *CTX_wm_space_data(const bContext *C);
struct ARegion *CTX_wm_region(const bContext *C);
void *CTX_wm_region_data(const bContext *C);
struct ARegion *CTX_wm_menu(const bContext *C);
+struct wmGizmoGroup *CTX_wm_gizmo_group(const bContext *C);
+struct wmMsgBus *CTX_wm_message_bus(const bContext *C);
struct ReportList *CTX_wm_reports(const bContext *C);
struct View3D *CTX_wm_view3d(const bContext *C);
@@ -158,14 +173,13 @@ struct SpaceFile *CTX_wm_space_file(const bContext *C);
struct SpaceSeq *CTX_wm_space_seq(const bContext *C);
struct SpaceOops *CTX_wm_space_outliner(const bContext *C);
struct SpaceNla *CTX_wm_space_nla(const bContext *C);
-struct SpaceTime *CTX_wm_space_time(const bContext *C);
struct SpaceNode *CTX_wm_space_node(const bContext *C);
-struct SpaceLogic *CTX_wm_space_logic(const bContext *C);
struct SpaceIpo *CTX_wm_space_graph(const bContext *C);
struct SpaceAction *CTX_wm_space_action(const bContext *C);
struct SpaceInfo *CTX_wm_space_info(const bContext *C);
struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C);
struct SpaceClip *CTX_wm_space_clip(const bContext *C);
+struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C);
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm);
void CTX_wm_window_set(bContext *C, struct wmWindow *win);
@@ -173,6 +187,7 @@ void CTX_wm_screen_set(bContext *C, struct bScreen *screen); /* to be removed */
void CTX_wm_area_set(bContext *C, struct ScrArea *sa);
void CTX_wm_region_set(bContext *C, struct ARegion *region);
void CTX_wm_menu_set(bContext *C, struct ARegion *menu);
+void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup);
const char *CTX_wm_operator_poll_msg_get(struct bContext *C);
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg);
@@ -209,11 +224,6 @@ short CTX_data_type_get(struct bContextDataResult *result);
bool CTX_data_equals(const char *member, const char *str);
bool CTX_data_dir(const char *member);
-#if 0
-void CTX_data_pointer_set(bContextDataResult *result, void *data);
-void CTX_data_list_add(bContextDataResult *result, void *data);
-#endif
-
#define CTX_DATA_BEGIN(C, Type, instance, member) \
{ \
ListBase ctx_data_list; \
@@ -243,9 +253,16 @@ int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBas
struct Main *CTX_data_main(const bContext *C);
struct Scene *CTX_data_scene(const bContext *C);
+struct LayerCollection *CTX_data_layer_collection(const bContext *C);
+struct Collection *CTX_data_collection(const bContext *C);
+struct ViewLayer *CTX_data_view_layer(const bContext *C);
+struct RenderEngineType *CTX_data_engine_type(const bContext *C);
struct ToolSettings *CTX_data_tool_settings(const bContext *C);
const char *CTX_data_mode_string(const bContext *C);
+int CTX_data_mode_enum_ex(
+ const struct Object *obedit, const struct Object *ob,
+ const eObjectMode object_mode);
int CTX_data_mode_enum(const bContext *C);
void CTX_data_main_set(bContext *C, struct Main *bmain);
@@ -288,18 +305,23 @@ int CTX_data_editable_bones(const bContext *C, ListBase *list);
struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C);
int CTX_data_selected_pose_bones(const bContext *C, ListBase *list);
+int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list);
int CTX_data_visible_pose_bones(const bContext *C, ListBase *list);
struct bGPdata *CTX_data_gpencil_data(const bContext *C);
struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C);
struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C);
-struct bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C);
-struct bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C);
-struct bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C);
+struct Brush *CTX_data_active_gpencil_brush(const bContext *C);
int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);
+struct Depsgraph *CTX_data_depsgraph(const bContext *C);
+
+/* Will Return NULL if depsgraph is not allocated yet.
+ * Only used by handful of operators which are run on file load.
+ */
+struct Depsgraph *CTX_data_depsgraph_on_load(const bContext *C);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_crazyspace.h b/source/blender/blenkernel/BKE_crazyspace.h
index ee6c5c57678..e9745ed50fa 100644
--- a/source/blender/blenkernel/BKE_crazyspace.h
+++ b/source/blender/blenkernel/BKE_crazyspace.h
@@ -38,23 +38,24 @@ struct Scene;
struct Object;
struct BMEditMesh;
struct Mesh;
+struct Depsgraph;
/* crazyspace.c */
float (*BKE_crazyspace_get_mapped_editverts(
- struct Scene *scene, struct Object *obedit))[3];
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *obedit))[3];
void BKE_crazyspace_set_quats_editmesh(
struct BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4],
const bool use_select);
void BKE_crazyspace_set_quats_mesh(
struct Mesh *me, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]);
int BKE_crazyspace_get_first_deform_matrices_editbmesh(
- struct Scene *, struct Object *, struct BMEditMesh *em,
+ struct Depsgraph *depsgraph, struct Scene *, struct Object *, struct BMEditMesh *em,
float (**deformmats)[3][3], float (**deformcos)[3]);
int BKE_sculpt_get_first_deform_matrices(
- struct Scene *scene, struct Object *ob,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
float (**deformmats)[3][3], float (**deformcos)[3]);
void BKE_crazyspace_build_sculpt(
- struct Scene *scene, struct Object *ob,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
float (**deformmats)[3][3], float (**deformcos)[3]);
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 5b7e5f9eebb..12e3492368b 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -36,6 +36,7 @@
struct BezTriple;
struct Curve;
struct EditNurb;
+struct Depsgraph;
struct GHash;
struct ListBase;
struct Main;
@@ -122,13 +123,14 @@ void BKE_curve_editNurb_keyIndex_free(struct GHash **keyindex);
void BKE_curve_editNurb_free(struct Curve *cu);
struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu);
-float *BKE_curve_make_orco(struct Scene *scene, struct Object *ob, int *r_numVerts);
+float *BKE_curve_make_orco(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, int *r_numVerts);
float *BKE_curve_surf_make_orco(struct Object *ob);
void BKE_curve_bevelList_free(struct ListBase *bev);
void BKE_curve_bevelList_make(struct Object *ob, struct ListBase *nurbs, bool for_render);
-void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob, struct ListBase *disp,
- const bool for_render, const bool use_render_resolution);
+void BKE_curve_bevel_make(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *disp,
+ const bool for_render, const bool use_render_resolution);
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
void BKE_curve_forward_diff_tangent_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
@@ -220,10 +222,17 @@ void BKE_nurb_handles_test(struct Nurb *nu, const bool use_handles);
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
-
-void BKE_curve_eval_geometry(struct EvaluationContext *eval_ctx,
- struct Curve *curve);
+void BKE_curve_eval_geometry(
+ struct Depsgraph *depsgraph,
+ struct Curve *curve);
+
+/* Draw Cache */
+enum {
+ BKE_CURVE_BATCH_DIRTY_ALL = 0,
+ BKE_CURVE_BATCH_DIRTY_SELECT,
+};
+void BKE_curve_batch_cache_dirty_tag(struct Curve *cu, int mode);
+void BKE_curve_batch_cache_free(struct Curve *cu);
/* curve_decimate.c */
unsigned int BKE_curve_decimate_bezt_array(
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index e75997cd394..23bc7ddd6fd 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -67,12 +67,14 @@ extern const CustomDataMask CD_MASK_EVERYTHING;
* CD_NUMTYPES elements, that indicate if a layer can be copied. */
/* add/copy/merge allocation types */
-#define CD_ASSIGN 0 /* use the data pointer */
-#define CD_CALLOC 1 /* allocate blank memory */
-#define CD_DEFAULT 2 /* allocate and set to default */
-#define CD_REFERENCE 3 /* use data pointers, set layer flag NOFREE */
-#define CD_DUPLICATE 4 /* do a full copy of all layers, only allowed if source
- * has same number of elements */
+typedef enum eCDAllocType {
+ CD_ASSIGN = 0, /* use the data pointer */
+ CD_CALLOC = 1, /* allocate blank memory */
+ CD_DEFAULT = 2, /* allocate and set to default */
+ CD_REFERENCE = 3, /* use data pointers, set layer flag NOFREE */
+ CD_DUPLICATE = 4, /* do a full copy of all layers, only allowed if source
+ * has same number of elements */
+} eCDAllocType;
#define CD_TYPE_AS_MASK(_type) (CustomDataMask)((CustomDataMask)1 << (CustomDataMask)(_type))
@@ -120,16 +122,18 @@ void CustomData_data_add(int type, void *data1, const void *data2);
/* initializes a CustomData object with the same layer setup as source.
* mask is a bitfield where (mask & (1 << (layer type))) indicates
* if a layer should be copied or not. alloctype must be one of the above. */
-void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem);
+void CustomData_copy(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem);
/* BMESH_TODO, not really a public function but readfile.c needs it */
void CustomData_update_typemap(struct CustomData *data);
/* same as the above, except that this will preserve existing layers, and only
* add the layers that were not there yet */
-bool CustomData_merge(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem);
+bool CustomData_merge(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem);
/* Reallocate custom data to a new element count.
* Only affects on data layers which are owned by the CustomData itself,
@@ -144,7 +148,7 @@ void CustomData_realloc(struct CustomData *data, int totelem);
* consistent with the new layout.*/
bool CustomData_bmesh_merge(
const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, struct BMesh *bm, const char htype);
+ CustomDataMask mask, eCDAllocType alloctype, struct BMesh *bm, const char htype);
/** NULL's all members and resets the typemap. */
void CustomData_reset(struct CustomData *data);
@@ -164,11 +168,13 @@ void CustomData_free_temporary(struct CustomData *data, int totelem);
* backed by an external data array. the different allocation types are
* defined above. returns the data of the layer.
*/
-void *CustomData_add_layer(struct CustomData *data, int type, int alloctype,
- void *layer, int totelem);
+void *CustomData_add_layer(
+ struct CustomData *data, int type, eCDAllocType alloctype,
+ void *layer, int totelem);
/*same as above but accepts a name */
-void *CustomData_add_layer_named(struct CustomData *data, int type, int alloctype,
- void *layer, int totelem, const char *name);
+void *CustomData_add_layer_named(
+ struct CustomData *data, int type, eCDAllocType alloctype,
+ void *layer, int totelem, const char *name);
/* frees the active or first data layer with the give type.
* returns 1 on success, 0 if no layer with the given type is found
@@ -218,13 +224,20 @@ void CustomData_copy_data(const struct CustomData *source,
struct CustomData *dest, int source_index,
int dest_index, int count);
void CustomData_copy_data_named(const struct CustomData *source,
- struct CustomData *dest, int source_index,
- int dest_index, int count);
+ struct CustomData *dest, int source_index,
+ int dest_index, int count);
void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count);
void CustomData_bmesh_copy_data(const struct CustomData *source,
struct CustomData *dest, void *src_block,
void **dest_block);
+/* Copies data of a single layer of a given type. */
+void CustomData_copy_layer_type_data(const struct CustomData *source,
+ struct CustomData *destination,
+ int type,
+ int source_index, int destination_index,
+ int count);
+
/* frees data in a CustomData object
* return 1 on success, 0 on failure
*/
@@ -376,15 +389,14 @@ void CustomData_validate_layer_name(const struct CustomData *data, int type, con
bool CustomData_verify_versions(struct CustomData *data, int index);
/*BMesh specific customdata stuff*/
-void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata,
- struct CustomData *ldata, int totloop, int totpoly);
-void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total);
-void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata);
-void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata);
+void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int totloop);
+void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *ldata, int total);
+void CustomData_bmesh_update_active_layers(struct CustomData *fdata, struct CustomData *ldata);
+void CustomData_bmesh_do_versions_update_active_layers(struct CustomData *fdata, struct CustomData *ldata);
void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, const char htype);
#ifndef NDEBUG
-bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback);
+bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback);
#endif
/* External file storage */
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index 2ee9d8d2408..7d0bb67c54d 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -38,6 +38,7 @@ extern "C" {
#include "BKE_customdata.h"
+struct Depsgraph;
struct Object;
struct Scene;
struct SpaceTransform;
@@ -129,11 +130,12 @@ enum {
};
void BKE_object_data_transfer_layout(
- struct Scene *scene, struct Object *ob_src, struct Object *ob_dst, const int data_types, const bool use_delete,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob_src,
+ struct Object *ob_dst, const int data_types, const bool use_delete,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX]);
bool BKE_object_data_transfer_mesh(
- struct Scene *scene,
+ struct Depsgraph *depsgraph, struct Scene *scene,
struct Object *ob_src, struct Object *ob_dst, const int data_types, const bool use_create,
const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
struct SpaceTransform *space_transform, const bool auto_transform,
@@ -141,9 +143,9 @@ bool BKE_object_data_transfer_mesh(
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
struct ReportList *reports);
-bool BKE_object_data_transfer_dm(
- struct Scene *scene,
- struct Object *ob_src, struct Object *ob_dst, struct DerivedMesh *dm_dst,
+bool BKE_object_data_transfer_ex(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob_src, struct Object *ob_dst, struct Mesh *me_dst,
const int data_types, bool use_create,
const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
struct SpaceTransform *space_transform, const bool auto_transform,
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index a20c5a4240c..a29f4197299 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -116,4 +116,6 @@ void BKE_defvert_extract_vgroup_to_polyweights(
struct MDeformVert *dvert, const int defgroup, const int num_verts, struct MLoop *loops, const int num_loops,
struct MPoly *polys, const int num_polys, float *r_weights, const bool invert_vgroup);
+void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight);
+
#endif /* __BKE_DEFORM_H__ */
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
deleted file mode 100644
index 4af4f696b07..00000000000
--- a/source/blender/blenkernel/BKE_depsgraph.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BKE_DEPSGRAPH_H__
-#define __BKE_DEPSGRAPH_H__
-
-/** \file BKE_depsgraph.h
- * \ingroup bke
- */
-
-/* Dependency Graph
- *
- * The dependency graph tracks relations between datablocks, and is used to
- * determine which datablocks need to be update based on dependencies and
- * visibility.
- *
- * It does not itself execute changes in objects, but rather sorts the objects
- * in the appropriate order and sets flags indicating they should be updated.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct ID;
-struct Main;
-struct Object;
-struct Scene;
-
-/* Dependency graph evaluation context
- *
- * This structure stores all the local dependency graph data,
- * which is needed for it's evaluation,
- */
-typedef struct EvaluationContext {
- int mode; /* evaluation mode */
- float ctime; /* evaluation time */
-} EvaluationContext;
-
-typedef enum eEvaluationMode {
- DAG_EVAL_VIEWPORT = 0, /* evaluate for OpenGL viewport */
- DAG_EVAL_PREVIEW = 1, /* evaluate for render with preview settings */
- DAG_EVAL_RENDER = 2, /* evaluate for render purposes */
-} eEvaluationMode;
-
-/* DagNode->eval_flags */
-enum {
- /* Regardless to curve->path animation flag path is to be evaluated anyway,
- * to meet dependencies with such a things as curve modifier and other guys
- * who're using curve deform, where_on_path and so.
- */
- DAG_EVAL_NEED_CURVE_PATH = 1,
- /* Scene evaluation would need to have object's data on CPU,
- * meaning no GPU shortcuts is allowed.
- */
- DAG_EVAL_NEED_CPU = 2,
-};
-
-/* Global initialization/deinitialization */
-void DAG_init(void);
-void DAG_exit(void);
-
-/* Build and Update
- *
- * DAG_scene_relations_update will rebuild the dependency graph for a given
- * scene if needed, and sort objects in the scene.
- *
- * DAG_relations_tag_update will clear all dependency graphs and mark them to
- * be rebuilt later. The graph is not rebuilt immediately to avoid slowdowns
- * when this function is call multiple times from different operators.
- *
- * DAG_scene_relations_rebuild forces an immediaterebuild of the dependency
- * graph, this is only needed in rare cases
- */
-
-void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
-void DAG_scene_relations_validate(struct Main *bmain, struct Scene *sce);
-void DAG_relations_tag_update(struct Main *bmain);
-void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
-void DAG_scene_free(struct Scene *sce);
-
-/* Update Tagging
- *
- * DAG_scene_update_flags will mark all objects that depend on time (animation,
- * physics, ..) to be recalculated, used when changing the current frame.
- *
- * DAG_on_visible_update will mark all objects that are visible for the first
- * time to be updated, for example on file load or changing layer visibility.
- *
- * DAG_id_tag_update will mark a given datablock to be updated. The flag indicates
- * a specific subset to be update (only object transform and data for now).
- *
- * DAG_id_type_tag marks a particular datablock type as having changing. This does
- * not cause any updates but is used by external render engines to detect if for
- * example a datablock was removed. */
-
-void DAG_scene_update_flags(struct Main *bmain, struct Scene *sce, unsigned int lay, const bool do_time, const bool do_invisible_flush);
-void DAG_on_visible_update(struct Main *bmain, const bool do_time);
-
-void DAG_id_tag_update(struct ID *id, short flag);
-void DAG_id_tag_update_ex(struct Main *bmain, struct ID *id, short flag);
-void DAG_id_type_tag(struct Main *bmain, short idtype);
-int DAG_id_type_tagged(struct Main *bmain, short idtype);
-
-/* Flushing Tags
- *
- * DAG_scene_flush_update flushes object recalculation flags immediately to other
- * dependencies. Do not use outside of depsgraph.c, this will be removed.
- *
- * DAG_ids_flush_tagged will flush datablock update flags flags to dependencies,
- * use this right before updating to mark all the needed datablocks for update.
- *
- * DAG_ids_check_recalc and DAG_ids_clear_recalc are used for external render
- * engines to detect changes. */
-
-void DAG_scene_flush_update(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
-void DAG_ids_flush_tagged(struct Main *bmain);
-void DAG_ids_check_recalc(struct Main *bmain, struct Scene *scene, bool time);
-void DAG_ids_clear_recalc(struct Main *bmain);
-
-/* Armature: sorts the bones according to dependencies between them */
-
-void DAG_pose_sort(struct Object *ob);
-
-/* Editors: callbacks to notify editors of datablock changes */
-
-void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id),
- void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated),
- void (*scene_pre_func)(struct Main *bmain, struct Scene *scene, bool time));
-
-void DAG_editors_update_pre(struct Main *bmain, struct Scene *scene, bool time);
-
-/* ** Threaded update ** */
-
-/* Initialize the DAG for threaded update. */
-void DAG_threaded_update_begin(struct Scene *scene,
- void (*func)(void *node, void *user_data),
- void *user_data);
-
-void DAG_threaded_update_handle_node_updated(void *node_v,
- void (*func)(void *node, void *user_data),
- void *user_data);
-
-/* Debugging: print dependency graph for scene or armature object to console */
-
-void DAG_print_dependencies(struct Main *bmain, struct Scene *scene, struct Object *ob);
-
-/* ************************ DAG querying ********************* */
-
-struct Object *DAG_get_node_object(void *node_v);
-const char *DAG_get_node_name(struct Scene *scene, void *node_v);
-short DAG_get_eval_flags_for_object(struct Scene *scene, void *object);
-bool DAG_is_acyclic(struct Scene *scene);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index a9cfa7b14ed..02c86642b11 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -57,8 +57,8 @@ enum {
/* prototypes */
-struct DerivedMesh;
-struct EvaluationContext;
+struct Depsgraph;
+struct Mesh;
struct ListBase;
struct Main;
struct Object;
@@ -87,23 +87,25 @@ void BKE_displist_count(struct ListBase *lb, int *totvert, int *totface, int *to
void BKE_displist_free(struct ListBase *lb);
bool BKE_displist_has_faces(struct ListBase *lb);
-void BKE_displist_make_surf(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, struct DerivedMesh **r_dm_final,
- const bool for_render, const bool for_orco, const bool use_render_resolution);
-void BKE_displist_make_curveTypes(struct Scene *scene, struct Object *ob, const bool for_orco);
-void BKE_displist_make_curveTypes_forRender(struct Scene *scene, struct Object *ob, struct ListBase *dispbase, struct DerivedMesh **r_dm_final,
- const bool for_orco, const bool use_render_resolution);
-void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
-void BKE_displist_make_mball(struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
-void BKE_displist_make_mball_forRender(struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
+void BKE_displist_make_surf(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase,
+ struct Mesh **r_final, const bool for_render, const bool for_orco, const bool use_render_resolution);
+void BKE_displist_make_curveTypes(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, const bool for_orco);
+void BKE_displist_make_curveTypes_forRender(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase,
+ struct Mesh **r_final, const bool for_orco, const bool use_render_resolution);
+void BKE_displist_make_curveTypes_forOrco(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
+void BKE_displist_make_mball(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+void BKE_displist_make_mball_forRender(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ListBase *dispbase);
bool BKE_displist_surfindex_get(DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4);
void BKE_displist_fill(struct ListBase *dispbase, struct ListBase *to, const float normal_proj[3], const bool flipnormal);
-float BKE_displist_calc_taper(struct Scene *scene, struct Object *taperobj, int cur, int tot);
-
-/* add Orco layer to the displist object which has got derived mesh and return orco */
-float *BKE_displist_make_orco(struct Scene *scene, struct Object *ob, struct DerivedMesh *dm_final,
- const bool for_render, const bool use_render_resolution);
+float BKE_displist_calc_taper(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *taperobj, int cur, int tot);
void BKE_displist_minmax(struct ListBase *dispbase, float min[3], float max[3]);
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index c265672da88..537a2946f36 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -27,9 +27,12 @@
* \ingroup bke
*/
-struct EvaluationContext;
+struct Depsgraph;
+struct DynamicPaintCanvasSettings;
+struct DynamicPaintModifierData;
struct Main;
struct Scene;
+struct ViewLayer;
/* Actual surface point */
typedef struct PaintSurfaceData {
@@ -62,9 +65,9 @@ typedef struct PaintWavePoint {
short state;
} PaintWavePoint;
-struct DerivedMesh *dynamicPaint_Modifier_do(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct DynamicPaintModifierData *pmd, struct Scene *scene,
- struct Object *ob, struct DerivedMesh *dm);
+struct Mesh *dynamicPaint_Modifier_do(
+ struct DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, struct Mesh *me);
void dynamicPaint_Modifier_free(struct DynamicPaintModifierData *pmd);
void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, struct DynamicPaintModifierData *tsmd);
@@ -88,9 +91,8 @@ struct DynamicPaintSurface *get_activeSurface(struct DynamicPaintCanvasSettings
/* image sequence baking */
int dynamicPaint_createUVSurface(struct Scene *scene, struct DynamicPaintSurface *surface, float *progress, short *do_update);
int dynamicPaint_calculateFrame(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx, struct DynamicPaintSurface *surface, struct Scene *scene,
- struct Object *cObject, int frame);
+ struct DynamicPaintSurface *surface, struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *cObject, int frame);
void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface, char *filename, short output_layer);
/* PaintPoint state */
diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h
index 2cae86d4c3b..de4efaf37b0 100644
--- a/source/blender/blenkernel/BKE_editmesh.h
+++ b/source/blender/blenkernel/BKE_editmesh.h
@@ -40,6 +40,8 @@ struct Mesh;
struct Scene;
struct DerivedMesh;
struct MeshStatVis;
+struct Depsgraph;
+struct EditMeshData;
/**
* This structure is used for mesh edit-mode.
@@ -62,8 +64,9 @@ typedef struct BMEditMesh {
struct BMLoop *(*looptris)[3];
int tottri;
+ struct Mesh *mesh_eval_final, *mesh_eval_cage;
+
/*derivedmesh stuff*/
- struct DerivedMesh *derivedFinal, *derivedCage;
CustomDataMask lastDataMask;
unsigned char (*derivedVertColor)[4];
int derivedVertColorLen;
@@ -88,17 +91,18 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em);
BMEditMesh *BKE_editmesh_from_object(struct Object *ob);
void BKE_editmesh_free_derivedmesh(BMEditMesh *em);
void BKE_editmesh_free(BMEditMesh *em);
-void BKE_editmesh_update_linked_customdata(BMEditMesh *em);
void BKE_editmesh_color_free(BMEditMesh *em);
void BKE_editmesh_color_ensure(BMEditMesh *em, const char htype);
float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3];
+void BKE_editmesh_lnorspace_update(BMEditMesh *em);
/* editderivedmesh.c */
/* should really be defined in editmesh.c, but they use 'EditDerivedBMesh' */
-void BKE_editmesh_statvis_calc(BMEditMesh *em, struct DerivedMesh *dm,
- const struct MeshStatVis *statvis);
+void BKE_editmesh_statvis_calc(
+ BMEditMesh *em, struct EditMeshData *emd, const struct MeshStatVis *statvis);
-float (*BKE_editmesh_vertexCos_get(struct BMEditMesh *em, struct Scene *scene, int *r_numVerts))[3];
+float (*BKE_editmesh_vertexCos_get(
+ struct Depsgraph *depsgraph, struct BMEditMesh *em, struct Scene *scene, int *r_numVerts))[3];
#endif /* __BKE_EDITMESH_H__ */
diff --git a/source/blender/blenkernel/BKE_bullet.h b/source/blender/blenkernel/BKE_editmesh_cache.h
index 84fcd20374f..aaaa79a0857 100644
--- a/source/blender/blenkernel/BKE_bullet.h
+++ b/source/blender/blenkernel/BKE_editmesh_cache.h
@@ -15,29 +15,22 @@
* along with this program; if 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_BULLET_H__
-#define __BKE_BULLET_H__
-/** \file BKE_bullet.h
+#ifndef __BKE_EDITMESH_CACHE_H__
+#define __BKE_EDITMESH_CACHE_H__
+
+/** \file BKE_editmesh_cache.h
* \ingroup bke
*/
-struct BulletSoftBody;
-
+struct BMEditMesh;
+struct EditMeshData;
-/* allocates and initializes general main data */
-extern struct BulletSoftBody *bsbNew(void);
+void BKE_editmesh_cache_ensure_poly_normals(struct BMEditMesh *em, struct EditMeshData *emd);
+void BKE_editmesh_cache_ensure_vert_normals(struct BMEditMesh *em, struct EditMeshData *emd);
-/* frees internal data and softbody itself */
-extern void bsbFree(struct BulletSoftBody *sb);
+void BKE_editmesh_cache_ensure_poly_centers(struct BMEditMesh *em, struct EditMeshData *emd);
-#endif
+#endif /* __BKE_EDITMESH_CACHE_H__ */
diff --git a/source/blender/blenkernel/BKE_editmesh_tangent.h b/source/blender/blenkernel/BKE_editmesh_tangent.h
new file mode 100644
index 00000000000..9553fbc1a5c
--- /dev/null
+++ b/source/blender/blenkernel/BKE_editmesh_tangent.h
@@ -0,0 +1,40 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Joseph Eagar.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_EDITMESH_TANGENT_H__
+#define __BKE_EDITMESH_TANGENT_H__
+
+/** \file BKE_editmesh_tangent.h
+ * \ingroup bke
+ */
+
+void BKE_editmesh_loop_tangent_calc(
+ BMEditMesh *em, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ CustomData *dm_loopdata_out,
+ const uint dm_loopdata_out_len,
+ short *tangent_mask_curr_p);
+
+#endif /* __BKE_EDITMESH_TANGENT_H__ */
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index bb5048a00f0..3d4154c572b 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -40,12 +40,14 @@
struct Object;
struct Scene;
struct ListBase;
-struct Group;
+struct Collection;
struct ParticleSimulationData;
struct ParticleData;
struct ParticleKey;
+struct Depsgraph;
+struct ViewLayer;
-struct EffectorWeights *BKE_add_effector_weights(struct Group *group);
+struct EffectorWeights *BKE_add_effector_weights(struct Collection *collection);
struct PartDeflect *object_add_collision_fields(int type);
/* Input to effector code */
@@ -93,6 +95,7 @@ typedef struct EffectorData {
typedef struct EffectorCache {
struct EffectorCache *next, *prev;
+ struct Depsgraph *depsgraph;
struct Scene *scene;
struct Object *ob;
struct ParticleSystem *psys;
@@ -109,11 +112,35 @@ typedef struct EffectorCache {
int flag;
} EffectorCache;
-void free_partdeflect(struct PartDeflect *pd);
-struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights, bool for_simulation);
-void pdEndEffectors(struct ListBase **effectors);
-void pdPrecalculateEffectors(struct ListBase *effectors);
-void pdDoEffectors(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *impulse);
+typedef struct EffectorRelation {
+ struct EffectorRelation *next, *prev;
+
+ struct Object *ob;
+ struct ParticleSystem *psys;
+ struct PartDeflect *pd;
+} EffectorRelation;
+
+void free_partdeflect(struct PartDeflect *pd);
+
+struct ListBase *BKE_effector_relations_create(
+ struct Depsgraph *depsgraph,
+ struct ViewLayer *view_layer,
+ struct Collection *collection);
+void BKE_effector_relations_free(struct ListBase *lb);
+
+struct ListBase *BKE_effectors_create(
+ struct Depsgraph *depsgraph,
+ struct Object *ob_src,
+ struct ParticleSystem *psys_src,
+ struct EffectorWeights *weights);
+void BKE_effectors_apply(
+ struct ListBase *effectors,
+ struct ListBase *colliders,
+ struct EffectorWeights *weights,
+ struct EffectedPoint *point,
+ float *force,
+ float *impulse);
+void BKE_effectors_free(struct ListBase *lb);
void pd_point_from_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, struct EffectedPoint *point);
void pd_point_from_loc(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point);
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 1dfcfd5e54f..ae87009b4a1 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -108,7 +108,11 @@ bool driver_get_variable_property(
struct ChannelDriver *driver, struct DriverTarget *dtar,
struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index);
-float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver, const float evaltime);
+bool BKE_driver_has_simple_expression(struct ChannelDriver *driver);
+void BKE_driver_invalidate_expression(struct ChannelDriver *driver, bool expr_changed, bool varname_changed);
+
+float evaluate_driver(struct PathResolvedRNA *anim_rna, struct ChannelDriver *driver,
+ struct ChannelDriver *driver_orig, const float evaltime);
/* ************** F-Curve Modifiers *************** */
@@ -269,6 +273,17 @@ bool BKE_fcurve_is_protected(struct FCurve *fcu);
/* The curve is an infinite cycle via Cycles modifier */
bool BKE_fcurve_is_cyclic(struct FCurve *fcu);
+/* Type of infinite cycle for a curve. */
+typedef enum eFCU_Cycle_Type {
+ FCU_CYCLE_NONE = 0,
+ /* The cycle repeats identically to the base range. */
+ FCU_CYCLE_PERFECT,
+ /* The cycle accumulates the change between start and end keys. */
+ FCU_CYCLE_OFFSET
+} eFCU_Cycle_Type;
+
+eFCU_Cycle_Type BKE_fcurve_get_cycle_type(struct FCurve *fcu);
+
/* -------- Curve Sanity -------- */
void calchandles_fcurve(struct FCurve *fcu);
@@ -282,7 +297,8 @@ void correct_bezpart(float v1[2], float v2[2], float v3[2], float v4[2]);
/* evaluate fcurve */
float evaluate_fcurve(struct FCurve *fcu, float evaltime);
-float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime);
+float evaluate_fcurve_driver(struct PathResolvedRNA *anim_rna, struct FCurve *fcu,
+ struct ChannelDriver *driver_orig, float evaltime);
/* evaluate fcurve and store value */
float calculate_fcurve(struct PathResolvedRNA *anim_rna, struct FCurve *fcu, float evaltime);
diff --git a/source/blender/blenkernel/BKE_fluidsim.h b/source/blender/blenkernel/BKE_fluidsim.h
index af5b146906a..4883f2392b0 100644
--- a/source/blender/blenkernel/BKE_fluidsim.h
+++ b/source/blender/blenkernel/BKE_fluidsim.h
@@ -36,10 +36,11 @@ struct Object;
struct Scene;
struct FluidsimSettings;
struct MVert;
+struct Depsgraph;
/* old interface */
-void initElbeemMesh(struct Scene *scene, struct Object *ob,
+void initElbeemMesh(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
int *numVertices, float **vertices,
int *numTriangles, int **triangles,
int useGlobalCoords, int modifierIndex);
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index ab527e9b393..32bd1c1be7d 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -49,8 +49,8 @@ typedef struct FreestyleModuleSettings FreestyleModuleSettings;
/* FreestyleConfig */
void BKE_freestyle_config_init(FreestyleConfig *config);
-void BKE_freestyle_config_free(FreestyleConfig *config);
-void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag);
+void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user);
+void BKE_freestyle_config_copy(FreestyleConfig *new_config, const FreestyleConfig *config, const int flag);
/* FreestyleConfig.modules */
FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config);
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 6ed32fc43ac..410c8bb3a65 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -102,7 +102,6 @@ typedef struct Global {
/* G.f */
#define G_RENDER_OGL (1 << 0)
#define G_SWAP_EXCHANGE (1 << 1)
-/* also uses G_FILE_AUTOPLAY */
/* #define G_RENDER_SHADOW (1 << 3) */ /* temp flag, removed */
#define G_BACKBUFSEL (1 << 4)
#define G_PICKSEL (1 << 5)
@@ -154,16 +153,6 @@ enum {
#define G_AUTOPACK (1 << 0)
#define G_FILE_COMPRESS (1 << 1)
-#define G_FILE_AUTOPLAY (1 << 2)
-
-#ifdef DNA_DEPRECATED_ALLOW
-#define G_FILE_ENABLE_ALL_FRAMES (1 << 3) /* deprecated */
-#define G_FILE_SHOW_DEBUG_PROPS (1 << 4) /* deprecated */
-#define G_FILE_SHOW_FRAMERATE (1 << 5) /* deprecated */
-/* #define G_FILE_SHOW_PROFILE (1 << 6) */ /* deprecated */
-/* #define G_FILE_LOCK (1 << 7) */ /* deprecated */
-/* #define G_FILE_SIGN (1 << 8) */ /* deprecated */
-#endif /* DNA_DEPRECATED_ALLOW */
#define G_FILE_USERPREFS (1 << 9)
#define G_FILE_NO_UI (1 << 10)
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 92e16f02e25..3b8df66668a 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -26,30 +26,50 @@
#ifndef __BKE_GPENCIL_H__
#define __BKE_GPENCIL_H__
-/** \file BKE_gpencil.h
- * \ingroup bke
- * \author Joshua Leung
- */
-
+ /** \file BKE_gpencil.h
+ * \ingroup bke
+ * \author Joshua Leung
+ */
+
+struct CurveMapping;
+struct Depsgraph;
+struct GpencilModifierData;
struct ToolSettings;
struct ListBase;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
+struct bGPDspoint;
struct bGPDstroke;
+struct Material;
struct bGPDpalette;
struct bGPDpalettecolor;
struct Main;
+struct BoundBox;
+struct Brush;
+struct Object;
+struct bDeformGroup;
+struct SimplifyGpencilModifierData;
+struct ArrayGpencilModifierData;
+struct LatticeGpencilModifierData;
+
+struct MDeformVert;
+struct MDeformWeight;
/* ------------ Grease-Pencil API ------------------ */
+void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
+void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
void BKE_gpencil_free_layers(struct ListBase *list);
-void BKE_gpencil_free_brushes(struct ListBase *list);
-void BKE_gpencil_free_palettes(struct ListBase *list);
-void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes);
+bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *derived_gpf);
+void BKE_gpencil_free_derived_frames(struct bGPdata *gpd);
+void BKE_gpencil_free(struct bGPdata *gpd, bool free_all);
+
+void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
+void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
@@ -60,21 +80,37 @@ struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[])
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
-void BKE_gpencil_copy_data(struct Main *bmain, struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag);
+void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
+struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src);
+
+void BKE_gpencil_copy_data(struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag);
+struct bGPdata *BKE_gpencil_copy(struct Main *bmain, const struct bGPdata *gpd);
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy);
void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
-struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
-struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
+/* materials */
+void BKE_gpencil_material_index_remove(struct bGPdata *gpd, int index);
+void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len);
+int BKE_gpencil_get_material_index(struct Object *ob, struct Material *ma);
+
+/* statistics functions */
+void BKE_gpencil_stats_update(struct bGPdata *gpd);
+
+/* Utilities for creating and populating GP strokes */
+/* - Number of values defining each point in the built-in data
+ * buffers for primitives (e.g. 2D Monkey)
+ */
+#define GP_PRIM_DATABUF_SIZE 5
-struct bGPDbrush *BKE_gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
-struct bGPDbrush *BKE_gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
-void BKE_gpencil_brush_init_presets(struct ToolSettings *ts);
+void BKE_gpencil_stroke_add_points(
+ struct bGPDstroke *gps,
+ const float *array, const int totpoints,
+ const float mat[4][4]);
+struct bGPDstroke *BKE_gpencil_add_stroke(struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness);
/* Stroke and Fill - Alpha Visibility Threshold */
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
@@ -103,20 +139,44 @@ struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
-struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
-void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
-void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *brush);
-
-struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd);
-void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
-void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
-void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd);
-
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette);
-void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
-void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
-struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
-void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
-void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
+struct Material *BKE_gpencil_get_material_from_brush(struct Brush *brush);
+struct Material *BKE_gpencil_material_ensure(struct Main *bmain, struct Object *ob);
+
+/* object boundbox */
+bool BKE_gpencil_data_minmax(
+ struct Object *ob, const struct bGPdata *gpd,
+ float r_min[3], float r_max[3]);
+bool BKE_gpencil_stroke_minmax(
+ const struct bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3]);
+bool BKE_gpencil_stroke_select_check(
+ const struct bGPDstroke *gps);
+
+struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob);
+void BKE_gpencil_centroid_3d(struct bGPdata *gpd, float r_centroid[3]);
+
+/* vertex groups */
+void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps);
+void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
+void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst);
+
+/* GPencil geometry evaluation */
+void BKE_gpencil_eval_geometry(struct Depsgraph *depsgraph, struct bGPdata *gpd);
+
+/* stroke geometry utilities */
+void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]);
+void BKE_gpencil_simplify_stroke(struct bGPDstroke *gps, float factor);
+void BKE_gpencil_simplify_fixed(struct bGPDstroke *gps);
+void BKE_gpencil_subdivide(struct bGPDstroke *gps, int level, int flag);
+
+void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]);
+
+bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf);
+bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence);
+
+void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
+float BKE_gpencil_multiframe_falloff_calc(struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
#endif /* __BKE_GPENCIL_H__ */
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
new file mode 100644
index 00000000000..91f368613cb
--- /dev/null
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -0,0 +1,270 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is: all of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_GPENCIL_MODIFIER_H__
+#define __BKE_GPENCIL_MODIFIER_H__
+
+/** \file BKE_gpencil_modifier.h
+ * \ingroup bke
+ */
+
+#include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */
+#include "BLI_compiler_attrs.h"
+#include "BKE_customdata.h"
+
+struct ID;
+struct Depsgraph;
+struct DerivedMesh;
+struct bContext; /* NOTE: bakeModifier() - called from UI - needs to create new datablocks, hence the need for this */
+struct Mesh;
+struct Object;
+struct Scene;
+struct ViewLayer;
+struct ListBase;
+struct bArmature;
+struct Main;
+struct GpencilModifierData;
+struct BMEditMesh;
+struct DepsNodeHandle;
+struct bGPDlayer;
+struct bGPDframe;
+struct bGPDstroke;
+struct ModifierUpdateDepsgraphContext;
+
+#define GPENCIL_MODIFIER_ACTIVE(_md, _is_render) (((_md->mode & eGpencilModifierMode_Realtime) && (_is_render == false)) || \
+ ((_md->mode & eGpencilModifierMode_Render) && (_is_render == true)))
+#define GPENCIL_MODIFIER_EDIT(_md, _is_edit) (((_md->mode & eGpencilModifierMode_Editmode) == 0) && (_is_edit))
+
+typedef enum {
+ /* Should not be used, only for None modifier type */
+ eGpencilModifierTypeType_None,
+
+ /* grease pencil modifiers */
+ eGpencilModifierTypeType_Gpencil,
+} GpencilModifierTypeType;
+
+typedef enum {
+ eGpencilModifierTypeFlag_SupportsMapping = (1 << 0),
+ eGpencilModifierTypeFlag_SupportsEditmode = (1 << 1),
+
+ /* For modifiers that support editmode this determines if the
+ * modifier should be enabled by default in editmode. This should
+ * only be used by modifiers that are relatively speedy and
+ * also generally used in editmode, otherwise let the user enable
+ * it by hand.
+ */
+ eGpencilModifierTypeFlag_EnableInEditmode = (1 << 2),
+
+ /* For modifiers that require original data and so cannot
+ * be placed after any non-deformative modifier.
+ */
+ eGpencilModifierTypeFlag_RequiresOriginalData = (1 << 3),
+
+ /* max one per type */
+ eGpencilModifierTypeFlag_Single = (1 << 4),
+
+ /* can't be added manually by user */
+ eGpencilModifierTypeFlag_NoUserAdd = (1 << 5),
+ /* can't be applied */
+ eGpencilModifierTypeFlag_NoApply = (1 << 6),
+} GpencilModifierTypeFlag;
+
+/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
+typedef void(*GreasePencilObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void(*GreasePencilIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
+typedef void(*GreasePencilTexWalkFunc)(void *userData, struct Object *ob, struct GpencilModifierData *md, const char *propname);
+
+typedef struct GpencilModifierTypeInfo {
+ /* The user visible name for this modifier */
+ char name[32];
+
+ /* The DNA struct name for the modifier data type, used to
+ * write the DNA data out.
+ */
+ char struct_name[32];
+
+ /* The size of the modifier data type, used by allocation. */
+ int struct_size;
+
+ GpencilModifierTypeType type;
+ GpencilModifierTypeFlag flags;
+
+
+ /********************* Non-optional functions *********************/
+
+ /* Copy instance data for this modifier type. Should copy all user
+ * level settings to the target modifier.
+ */
+ void (*copyData)(const struct GpencilModifierData *md, struct GpencilModifierData *target);
+
+ /* Callback for GP "stroke" modifiers that operate on the
+ * shape and parameters of the provided strokes (e.g. Thickness, Noise, etc.)
+ *
+ * The gpl parameter contains the GP layer that the strokes come from.
+ * While access is provided to this data, you should not directly access
+ * the gpl->frames data from the modifier. Instead, use the gpf parameter
+ * instead.
+ *
+ * The gps parameter contains the GP stroke to operate on. This is usually a copy
+ * of the original (unmodified and saved to files) stroke data.
+ */
+ void (*deformStroke)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
+ struct Object *ob, struct bGPDlayer *gpl, struct bGPDstroke *gps);
+
+ /* Callback for GP "geometry" modifiers that create extra geometry
+ * in the frame (e.g. Array)
+ *
+ * The gpf parameter contains the GP frame/strokes to operate on. This is
+ * usually a copy of the original (unmodified and saved to files) stroke data.
+ * Modifiers should only add any generated strokes to this frame (and not one accessed
+ * via the gpl parameter).
+ *
+ * The modifier_index parameter indicates where the modifier is
+ * in the modifier stack in relation to other modifiers.
+ */
+ void (*generateStrokes)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
+ struct Object *ob, struct bGPDlayer *gpl, struct bGPDframe *gpf);
+
+ /* Bake-down GP modifier's effects into the GP datablock.
+ *
+ * This gets called when the user clicks the "Apply" button in the UI.
+ * As such, this callback needs to go through all layers/frames in the
+ * datablock, mutating the geometry and/or creating new datablocks/objects
+ */
+ void (*bakeModifier)(struct Main *bmain, struct Depsgraph *depsgraph,
+ struct GpencilModifierData *md, struct Object *ob);
+
+
+ /********************* Optional functions *********************/
+
+ /* Callback for GP "time" modifiers that offset keyframe time
+ * Returns the frame number to be used after apply the modifier. This is
+ * usually an offset of the animation for duplicated datablocks.
+ *
+ * This function is optional.
+ */
+ int (*remapTime)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *ob, struct bGPDlayer *gpl, int cfra);
+
+ /* Initialize new instance data for this modifier type, this function
+ * should set modifier variables to their default values.
+ *
+ * This function is optional.
+ */
+ void (*initData)(struct GpencilModifierData *md);
+
+ /* Free internal modifier data variables, this function should
+ * not free the md variable itself.
+ *
+ * This function is optional.
+ */
+ void (*freeData)(struct GpencilModifierData *md);
+
+ /* Return a boolean value indicating if this modifier is able to be
+ * calculated based on the modifier data. This is *not* regarding the
+ * md->flag, that is tested by the system, this is just if the data
+ * validates (for example, a lattice will return false if the lattice
+ * object is not defined).
+ *
+ * This function is optional (assumes never disabled if not present).
+ */
+ bool (*isDisabled)(struct GpencilModifierData *md, int userRenderParams);
+
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ void (*updateDepsgraph)(struct GpencilModifierData *md,
+ const struct ModifierUpdateDepsgraphContext *ctx);
+
+ /* Should return true if the modifier needs to be recalculated on time
+ * changes.
+ *
+ * This function is optional (assumes false if not present).
+ */
+ bool (*dependsOnTime)(struct GpencilModifierData *md);
+
+
+ /* Should call the given walk function on with a pointer to each Object
+ * pointer that the modifier data stores. This is used for linking on file
+ * load and for unlinking objects or forwarding object references.
+ *
+ * This function is optional.
+ */
+ void (*foreachObjectLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilObjectWalkFunc walk, void *userData);
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the modifier data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional. If it is not present, foreachObjectLink
+ * will be used.
+ */
+ void (*foreachIDLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilIDWalkFunc walk, void *userData);
+
+ /* Should call the given walk function for each texture that the
+ * modifier data stores. This is used for finding all textures in
+ * the context for the UI.
+ *
+ * This function is optional. If it is not present, it will be
+ * assumed the modifier has no textures.
+ */
+ void (*foreachTexLink)(struct GpencilModifierData *md, struct Object *ob,
+ GreasePencilTexWalkFunc walk, void *userData);
+} GpencilModifierTypeInfo;
+
+/* Initialize modifier's global data (type info and some common global storages). */
+void BKE_gpencil_modifier_init(void);
+
+const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
+void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
+void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
+bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
+bool BKE_gpencil_modifier_dependsOnTime(struct GpencilModifierData *md);
+struct GpencilModifierData *BKE_gpencil_modifiers_findByType(struct Object *ob, GpencilModifierType type);
+struct GpencilModifierData *BKE_gpencil_modifiers_findByName(struct Object *ob, const char *name);
+void BKE_gpencil_modifier_copyData_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst);
+void BKE_gpencil_modifier_copyData(struct GpencilModifierData *md, struct GpencilModifierData *target);
+void BKE_gpencil_modifier_copyData_ex(struct GpencilModifierData *md, struct GpencilModifierData *target, const int flag);
+void BKE_gpencil_modifiers_foreachIDLink(struct Object *ob, GreasePencilIDWalkFunc walk, void *userData);
+void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob, GreasePencilTexWalkFunc walk, void *userData);
+
+bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
+bool BKE_gpencil_has_time_modifiers(struct Object *ob);
+
+void BKE_gpencil_stroke_modifiers(
+ struct Depsgraph *depsgraph, struct Object *ob,
+ struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps, bool is_render);
+void BKE_gpencil_geometry_modifiers(
+ struct Depsgraph *depsgraph, struct Object *ob,
+ struct bGPDlayer *gpl, struct bGPDframe *gpf, bool is_render);
+int BKE_gpencil_time_modifier(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ struct bGPDlayer *gpl, int cfra, bool is_render);
+
+void BKE_gpencil_lattice_init(struct Object *ob);
+void BKE_gpencil_lattice_clear(struct Object *ob);
+
+#endif /* __BKE_GPENCIL_MODIFIER_H__ */
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
deleted file mode 100644
index 9824814990f..00000000000
--- a/source/blender/blenkernel/BKE_group.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_GROUP_H__
-#define __BKE_GROUP_H__
-
-/** \file BKE_group.h
- * \ingroup bke
- * \since March 2001
- * \author nzc
- */
-
-struct Base;
-struct EvaluationContext;
-struct Group;
-struct Main;
-struct Object;
-struct Scene;
-
-void BKE_group_free(struct Group *group);
-struct Group *BKE_group_add(struct Main *bmain, const char *name);
-void BKE_group_copy_data(struct Main *bmain, struct Group *group_dst, const struct Group *group_src, const int flag);
-struct Group *BKE_group_copy(struct Main *bmain, const struct Group *group);
-void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local);
-bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
-bool BKE_group_object_unlink(
- struct Main *bmain, struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
-struct Group *BKE_group_object_find(struct Main *bmain, struct Group *group, struct Object *ob);
-bool BKE_group_object_exists(struct Group *group, struct Object *ob);
-bool BKE_group_object_cyclic_check(struct Main *bmain, struct Object *object, struct Group *group);
-bool BKE_group_is_animated(struct Group *group, struct Object *parent);
-
-void BKE_group_handle_recalc_and_update(
- struct Main *bmain, struct EvaluationContext *eval_ctx,
- struct Scene *scene, struct Object *parent, struct Group *group);
-
-#endif /* __BKE_GROUP_H__ */
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 686dba21283..7a5262e0a14 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -36,18 +36,53 @@
typedef void (*DrawInfoFreeFP)(void *drawinfo);
+enum {
+ /** ID preview: obj is #ID. */
+ ICON_DATA_ID = 0,
+ /** Preview: obj is #PreviewImage */
+ ICON_DATA_PREVIEW,
+ /** 2D triangles: obj is #Icon_Geom */
+ ICON_DATA_GEOM,
+ /** Studiolight */
+ ICON_DATA_STUDIOLIGHT,
+ /** GPencil Layer color preview (annotations): obj is #bGPDlayer */
+ ICON_DATA_GPLAYER,
+};
+
struct Icon {
void *drawinfo;
+ /**
+ * Data defined by #obj_type
+ * \note for #ICON_DATA_GEOM the memory is owned by the icon,
+ * could be made into a flag if we want that to be optional.
+ */
void *obj;
+ char obj_type;
+ /** Internal use only. */
+ char flag;
/** #ID_Type or 0 when not used for ID preview. */
short id_type;
DrawInfoFreeFP drawinfo_free;
};
+/** Used for #ICON_DATA_GEOM, assigned to #Icon.obj. */
+struct Icon_Geom {
+ int icon_id;
+ int coords_len;
+ int coords_range[2];
+ const unsigned char (*coords)[2];
+ const unsigned char (*colors)[4];
+ /* when not NULL, the memory of coords and colors is a sub-region of this pointer. */
+ const void *mem;
+};
+
typedef struct Icon Icon;
+struct ImBuf;
struct PreviewImage;
struct ID;
+struct StudioLight;
+struct bGPDlayer;
enum eIconSizes;
@@ -56,6 +91,9 @@ void BKE_icons_init(int first_dyn_id);
/* return icon id for library object or create new icon if not found */
int BKE_icon_id_ensure(struct ID *id);
+/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */
+int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl);
+
int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
/* retrieve icon for id */
@@ -68,7 +106,8 @@ void BKE_icon_set(const int icon_id, struct Icon *icon);
/* remove icon and free data if library object becomes invalid */
void BKE_icon_id_delete(struct ID *id);
-void BKE_icon_delete(const int icon_id);
+bool BKE_icon_delete(const int icon_id);
+bool BKE_icon_delete_unmanaged(const int icon_id);
/* report changes - icon needs to be recalculated */
void BKE_icon_changed(const int icon_id);
@@ -120,6 +159,16 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read(
void BKE_previewimg_cached_release(const char *name);
void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv);
+int BKE_icon_geom_ensure(struct Icon_Geom *geom);
+struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len);
+struct Icon_Geom *BKE_icon_geom_from_file(const char *filename);
+
+struct ImBuf *BKE_icon_geom_rasterize(
+ const struct Icon_Geom *geom,
+ const unsigned int size_x, const unsigned int size_y);
+
+int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type);
+
#define ICON_RENDER_DEFAULT_HEIGHT 32
#endif /* __BKE_ICONS_H__ */
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 48a00462dd1..6df31db7b83 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -32,6 +32,10 @@
#include "BLI_compiler_attrs.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct IDProperty;
struct ID;
@@ -91,6 +95,7 @@ void IDP_ReplaceGroupInGroup(struct IDProperty *dest, const struct IDProperty *s
void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
void IDP_ReplaceInGroup_ex(struct IDProperty *group, struct IDProperty *prop, struct IDProperty *prop_exist);
void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite) ATTR_NONNULL();
+void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag) ATTR_NONNULL();
bool IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop) ATTR_NONNULL();
bool IDP_InsertToGroup(struct IDProperty *group, struct IDProperty *previous,
struct IDProperty *pnew) ATTR_NONNULL(1 /* group */, 3 /* pnew */);
@@ -118,6 +123,8 @@ void IDP_ClearProperty(IDProperty *prop);
void IDP_RelinkProperty(struct IDProperty *prop);
+void IDP_Reset(IDProperty *prop, const IDProperty *reference);
+
#define IDP_Int(prop) ((prop)->data.val)
#define IDP_Array(prop) ((prop)->data.pointer)
/* C11 const correctness for casts */
@@ -154,4 +161,8 @@ void IDP_repr_fn(
void *user_data);
void IDP_print(const struct IDProperty *prop);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __BKE_IDPROP_H__ */
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index bd9aeb1ab11..4bcb8e0c15d 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -114,8 +114,6 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const struc
struct anim *openanim(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE]);
struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE]);
-void BKE_image_de_interlace(struct Image *ima, int odd);
-
void BKE_image_make_local(struct Main *bmain, struct Image *ima, const bool lib_local);
void BKE_image_tag_time(struct Image *ima);
@@ -213,9 +211,9 @@ struct Image *BKE_image_verify_viewer(struct Main *bmain, int type, const char *
void BKE_image_verify_viewer_views(const struct RenderData *rd, struct Image *ima, struct ImageUser *iuser);
/* called on frame change or before render */
-void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
-void BKE_image_user_check_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
-int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, int fieldnr, bool *r_is_in_range);
+void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra);
+void BKE_image_user_check_frame_calc(struct ImageUser *iuser, int cfra);
+int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range);
void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path);
void BKE_image_update_frame(const struct Main *bmain, int cfra);
@@ -271,7 +269,7 @@ bool BKE_image_scale(struct Image *image, int width, int height);
bool BKE_image_has_alpha(struct Image *image);
/* check if texture has gpu texture code */
-bool BKE_image_has_bindcode(struct Image *ima);
+bool BKE_image_has_opengl_texture(struct Image *ima);
void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *width, int *height);
void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float size[2]);
@@ -296,6 +294,12 @@ void BKE_image_file_format_set(struct Image *image, int ftype, const struct ImbF
bool BKE_image_has_loaded_ibuf(struct Image *image);
struct ImBuf *BKE_image_get_ibuf_with_name(struct Image *image, const char *name);
struct ImBuf *BKE_image_get_first_ibuf(struct Image *image);
+
+struct RenderSlot *BKE_image_add_renderslot(struct Image *ima, const char *name);
+bool BKE_image_remove_renderslot(struct Image *ima, struct ImageUser *iuser, int slot);
+struct RenderSlot *BKE_image_get_renderslot(struct Image *ima, int slot);
+bool BKE_image_clear_renderslot(struct Image *ima, struct ImageUser *iuser, int slot);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 2f953e57d71..73a6f5047b2 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -80,29 +80,19 @@ struct KeyBlock *BKE_keyblock_find_name(struct Key *key, const char name[]);
void BKE_keyblock_copy_settings(struct KeyBlock *kb_dst, const struct KeyBlock *kb_src);
char *BKE_keyblock_curval_rnapath_get(struct Key *key, struct KeyBlock *kb);
-// needed for the GE
-typedef struct WeightsArrayCache {
- int num_defgroup_weights;
- float **defgroup_weights;
-} WeightsArrayCache;
-
-float **BKE_keyblock_get_per_block_weights(struct Object *ob, struct Key *key, struct WeightsArrayCache *cache);
-void BKE_keyblock_free_per_block_weights(struct Key *key, float **per_keyblock_weights, struct WeightsArrayCache *cache);
-void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, struct Key *key, struct KeyBlock *actkb,
- float **per_keyblock_weights, const int mode);
-
/* conversion functions */
/* Note: 'update_from' versions do not (re)allocate mem in kb, while 'convert_from' do. */
void BKE_keyblock_update_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_from_lattice(struct Lattice *lt, struct KeyBlock *kb);
void BKE_keyblock_convert_to_lattice(struct KeyBlock *kb, struct Lattice *lt);
+int BKE_keyblock_curve_element_count(struct ListBase *nurb);
void BKE_keyblock_update_from_curve(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb);
void BKE_keyblock_convert_from_curve(struct Curve *cu, struct KeyBlock *kb, struct ListBase *nurb);
void BKE_keyblock_convert_to_curve(struct KeyBlock *kb, struct Curve *cu, struct ListBase *nurb);
void BKE_keyblock_update_from_mesh(struct Mesh *me, struct KeyBlock *kb);
-void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct KeyBlock *kb);
+void BKE_keyblock_convert_from_mesh(struct Mesh *me, struct Key *key, struct KeyBlock *kb);
void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct Mesh *me);
void BKE_keyblock_mesh_calc_normals(
struct KeyBlock *kb, struct Mesh *mesh, float (*r_vertnors)[3], float (*r_polynors)[3], float (*r_loopnors)[3]);
diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h
index 3673e657b33..aa655c66477 100644
--- a/source/blender/blenkernel/BKE_lamp.h
+++ b/source/blender/blenkernel/BKE_lamp.h
@@ -50,8 +50,6 @@ struct Lamp *BKE_lamp_localize(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool lib_local);
void BKE_lamp_free(struct Lamp *la);
-void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index f7d006785d2..2e093ba11a2 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -38,11 +38,13 @@
struct Lattice;
struct Main;
+struct Mesh;
struct Object;
struct Scene;
-struct DerivedMesh;
struct BPoint;
struct MDeformVert;
+struct Depsgraph;
+struct bGPDstroke;
void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
void BKE_lattice_init(struct Lattice *lt);
@@ -53,7 +55,6 @@ void BKE_lattice_free(struct Lattice *lt);
void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local);
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
-struct LatticeDeformData;
struct LatticeDeformData *init_latt_deform(struct Object *oblatt, struct Object *ob) ATTR_WARN_UNUSED_RESULT;
void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight);
void end_latt_deform(struct LatticeDeformData *lattice_deform_data);
@@ -61,23 +62,28 @@ void end_latt_deform(struct LatticeDeformData *lattice_deform_data);
bool object_deform_mball(struct Object *ob, struct ListBase *dispbase);
void outside_lattice(struct Lattice *lt);
-void curve_deform_verts(struct Scene *scene, struct Object *cuOb, struct Object *target,
- struct DerivedMesh *dm, float (*vertexCos)[3],
- int numVerts, const char *vgroup, short defaxis);
-void curve_deform_vector(struct Scene *scene, struct Object *cuOb, struct Object *target,
- float orco[3], float vec[3], float mat[3][3], int no_rot_axis);
-
-void lattice_deform_verts(struct Object *laOb, struct Object *target,
- struct DerivedMesh *dm, float (*vertexCos)[3],
- int numVerts, const char *vgroup, float influence);
-void armature_deform_verts(struct Object *armOb, struct Object *target,
- struct DerivedMesh *dm, float (*vertexCos)[3],
- float (*defMats)[3][3], int numVerts, int deformflag,
- float (*prevCos)[3], const char *defgrp_name);
+void curve_deform_verts(
+ struct Object *cuOb, struct Object *target,
+ struct Mesh *mesh, float (*vertexCos)[3],
+ int numVerts, const char *vgroup, short defaxis);
+void curve_deform_vector(
+ struct Object *cuOb, struct Object *target,
+ float orco[3], float vec[3], float mat[3][3], int no_rot_axis);
+
+void lattice_deform_verts(
+ struct Object *laOb, struct Object *target,
+ struct Mesh *mesh, float (*vertexCos)[3],
+ int numVerts, const char *vgroup, float influence);
+void armature_deform_verts(
+ struct Object *armOb, struct Object *target,
+ const struct Mesh *mesh, float (*vertexCos)[3],
+ float (*defMats)[3][3], int numVerts, int deformflag,
+ float (*prevCos)[3], const char *defgrp_name,
+ struct bGPDstroke *gps);
float (*BKE_lattice_vertexcos_get(struct Object *ob, int *r_numVerts))[3];
void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3]);
-void BKE_lattice_modifiers_calc(struct Scene *scene, struct Object *ob);
+void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
struct MDeformVert *BKE_lattice_deform_verts_get(struct Object *lattice);
struct BPoint *BKE_lattice_active_point_get(struct Lattice *lt);
@@ -90,6 +96,8 @@ void BKE_lattice_center_bounds(struct Lattice *lt, float cent[3]);
void BKE_lattice_translate(struct Lattice *lt, float offset[3], bool do_keys);
void BKE_lattice_transform(struct Lattice *lt, float mat[4][4], bool do_keys);
+bool BKE_lattice_is_any_selected(const struct Lattice *lt);
+
int BKE_lattice_index_from_uvw(struct Lattice *lt, const int u, const int v, const int w);
void BKE_lattice_index_to_uvw(struct Lattice *lt, const int index, int *r_u, int *r_v, int *r_w);
int BKE_lattice_index_flip(struct Lattice *lt, const int index,
@@ -99,9 +107,17 @@ void BKE_lattice_bitmap_from_flag(struct Lattice *lt, unsigned int *bitmap, cons
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
+struct Depsgraph;
-void BKE_lattice_eval_geometry(struct EvaluationContext *eval_ctx,
+void BKE_lattice_eval_geometry(struct Depsgraph *depsgraph,
struct Lattice *latt);
+/* Draw Cache */
+enum {
+ BKE_LATTICE_BATCH_DIRTY_ALL = 0,
+ BKE_LATTICE_BATCH_DIRTY_SELECT,
+};
+void BKE_lattice_batch_cache_dirty_tag(struct Lattice *lt, int mode);
+void BKE_lattice_batch_cache_free(struct Lattice *lt);
+
#endif /* __BKE_LATTICE_H__ */
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
new file mode 100644
index 00000000000..2d736b41d1a
--- /dev/null
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -0,0 +1,396 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_LAYER_H__
+#define __BKE_LAYER_H__
+
+/** \file blender/blenkernel/BKE_layer.h
+ * \ingroup bke
+ */
+
+#include "BKE_collection.h"
+
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TODO_LAYER_OVERRIDE /* CollectionOverride */
+#define TODO_LAYER_OPERATORS /* collection mamanger and property panel operators */
+#define TODO_LAYER /* generic todo */
+
+#define ROOT_PROP "root"
+
+struct Base;
+struct Collection;
+struct Depsgraph;
+struct ID;
+struct IDProperty;
+struct LayerCollection;
+struct ListBase;
+struct Main;
+struct Object;
+struct RenderEngine;
+struct Scene;
+struct ViewLayer;
+struct WorkSpace;
+
+struct ViewLayer *BKE_view_layer_default_view(const struct Scene *scene);
+struct ViewLayer *BKE_view_layer_default_render(const struct Scene *scene);
+struct ViewLayer *BKE_view_layer_find(const struct Scene *scene, const char *layer_name);
+struct ViewLayer *BKE_view_layer_add(struct Scene *scene, const char *name);
+
+/* DEPRECATED */
+struct ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const struct Scene *scene);
+
+void BKE_view_layer_free(struct ViewLayer *view_layer);
+void BKE_view_layer_free_ex(struct ViewLayer *view_layer, const bool do_id_user);
+
+void BKE_view_layer_selected_objects_tag(struct ViewLayer *view_layer, const int tag);
+
+struct Object *BKE_view_layer_camera_find(struct ViewLayer *view_layer);
+struct ViewLayer *BKE_view_layer_find_from_collection(const struct Scene *scene, struct LayerCollection *lc);
+struct Base *BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob);
+void BKE_view_layer_base_deselect_all(struct ViewLayer *view_layer);
+
+void BKE_view_layer_base_select(struct Base *selbase);
+void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, struct Base *selbase);
+
+void BKE_view_layer_copy_data(
+ struct Scene *scene_dst, const struct Scene *scene_src,
+ struct ViewLayer *view_layer_dst, const struct ViewLayer *view_layer_src,
+ const int flag);
+
+void BKE_view_layer_rename(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, const char *name);
+
+struct LayerCollection *BKE_layer_collection_get_active(struct ViewLayer *view_layer);
+bool BKE_layer_collection_activate(struct ViewLayer *view_layer, struct LayerCollection *lc);
+struct LayerCollection *BKE_layer_collection_activate_parent(struct ViewLayer *view_layer, struct LayerCollection *lc);
+
+int BKE_layer_collection_count(struct ViewLayer *view_layer);
+
+struct LayerCollection *BKE_layer_collection_from_index(struct ViewLayer *view_layer, const int index);
+int BKE_layer_collection_findindex(struct ViewLayer *view_layer, const struct LayerCollection *lc);
+
+void BKE_main_collection_sync(const struct Main *bmain);
+void BKE_scene_collection_sync(const struct Scene *scene);
+void BKE_layer_collection_sync(const struct Scene *scene, struct ViewLayer *view_layer);
+
+void BKE_main_collection_sync_remap(const struct Main *bmain);
+
+struct LayerCollection *BKE_layer_collection_first_from_scene_collection(
+ struct ViewLayer *view_layer, const struct Collection *collection);
+bool BKE_view_layer_has_collection(
+ struct ViewLayer *view_layer, const struct Collection *collection);
+bool BKE_scene_has_object(
+ struct Scene *scene, struct Object *ob);
+
+/* selection and hiding */
+
+bool BKE_layer_collection_objects_select(
+ struct ViewLayer *view_layer, struct LayerCollection *lc, bool deselect);
+bool BKE_layer_collection_has_selected_objects(
+ struct ViewLayer *view_layer, struct LayerCollection *lc);
+
+void BKE_base_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, bool extend);
+void BKE_layer_collection_set_visible(struct Scene *scene, struct ViewLayer *view_layer, struct LayerCollection *lc, bool extend);
+
+/* override */
+
+void BKE_override_view_layer_datablock_add(
+ struct ViewLayer *view_layer, int id_type, const char *data_path, const struct ID *owner_id);
+void BKE_override_view_layer_int_add(
+ struct ViewLayer *view_layer, int id_type, const char *data_path, const int value);
+
+void BKE_override_layer_collection_boolean_add(
+ struct LayerCollection *layer_collection, int id_type, const char *data_path, const bool value);
+
+/* evaluation */
+
+void BKE_layer_eval_view_layer(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct ViewLayer *view_layer);
+
+void BKE_layer_eval_view_layer_indexed(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ int view_layer_index);
+
+/* iterators */
+
+void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_visible_objects_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *iter);
+
+struct ObjectsInModeIteratorData {
+ int object_mode;
+ struct ViewLayer *view_layer;
+ struct Base *base_active;
+};
+
+void BKE_view_layer_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_renderable_objects_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_renderable_objects_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *iter);
+
+void BKE_view_layer_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in);
+void BKE_view_layer_visible_bases_iterator_next(BLI_Iterator *iter);
+void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
+
+#define FOREACH_SELECTED_OBJECT_BEGIN(view_layer, _instance) \
+ ITER_BEGIN(BKE_view_layer_selected_objects_iterator_begin, \
+ BKE_view_layer_selected_objects_iterator_next, \
+ BKE_view_layer_selected_objects_iterator_end, \
+ view_layer, Object *, _instance)
+
+#define FOREACH_SELECTED_OBJECT_END \
+ ITER_END
+
+#define FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(view_layer, _instance) \
+ ITER_BEGIN(BKE_view_layer_selected_editable_objects_iterator_begin, \
+ BKE_view_layer_selected_editable_objects_iterator_next, \
+ BKE_view_layer_selected_editable_objects_iterator_end, \
+ view_layer, Object *, _instance)
+
+#define FOREACH_SELECTED_EDITABLE_OBJECT_END \
+ ITER_END
+
+#define FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, _instance) \
+ ITER_BEGIN(BKE_view_layer_visible_objects_iterator_begin, \
+ BKE_view_layer_visible_objects_iterator_next, \
+ BKE_view_layer_visible_objects_iterator_end, \
+ view_layer, Object *, _instance)
+
+#define FOREACH_VISIBLE_OBJECT_END \
+ ITER_END
+
+
+#define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _object_mode, _instance) \
+{ \
+ struct ObjectsInModeIteratorData data_ = { \
+ .object_mode = _object_mode, \
+ .view_layer = _view_layer, \
+ .base_active = _view_layer->basact, \
+ }; \
+ ITER_BEGIN(BKE_view_layer_bases_in_mode_iterator_begin, \
+ BKE_view_layer_bases_in_mode_iterator_next, \
+ BKE_view_layer_bases_in_mode_iterator_end, \
+ &data_, Base *, _instance)
+
+#define FOREACH_BASE_IN_MODE_END \
+ ITER_END; \
+} ((void)0)
+
+#define FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _instance) \
+ FOREACH_BASE_IN_MODE_BEGIN(_view_layer, OB_MODE_EDIT, _instance)
+
+#define FOREACH_BASE_IN_EDIT_MODE_END \
+ FOREACH_BASE_IN_MODE_END
+
+#define FOREACH_OBJECT_IN_MODE_BEGIN(_view_layer, _object_mode, _instance) \
+ FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _object_mode, _base) { \
+ Object *_instance = _base->object;
+
+#define FOREACH_OBJECT_IN_MODE_END \
+ } FOREACH_BASE_IN_MODE_END
+
+#define FOREACH_OBJECT_IN_EDIT_MODE_BEGIN(_view_layer, _instance) \
+ FOREACH_BASE_IN_EDIT_MODE_BEGIN(_view_layer, _base) { \
+ Object *_instance = _base->object;
+
+#define FOREACH_OBJECT_IN_EDIT_MODE_END \
+ } FOREACH_BASE_IN_EDIT_MODE_END
+
+#define FOREACH_SELECTED_BASE_BEGIN(view_layer, _instance) \
+ ITER_BEGIN(BKE_view_layer_selected_bases_iterator_begin, \
+ BKE_view_layer_selected_bases_iterator_next, \
+ BKE_view_layer_selected_bases_iterator_end, \
+ view_layer, Base *, _instance)
+
+#define FOREACH_SELECTED_BASE_END \
+ ITER_END
+
+#define FOREACH_VISIBLE_BASE_BEGIN(view_layer, _instance) \
+ ITER_BEGIN(BKE_view_layer_visible_bases_iterator_begin, \
+ BKE_view_layer_visible_bases_iterator_next, \
+ BKE_view_layer_visible_bases_iterator_end, \
+ view_layer, Base *, _instance)
+
+#define FOREACH_VISIBLE_BASE_END \
+ ITER_END
+
+
+#define FOREACH_OBJECT_BEGIN(view_layer, _instance) \
+{ \
+ Object *_instance; \
+ Base *_base; \
+ for (_base = (view_layer)->object_bases.first; _base; _base = _base->next) { \
+ _instance = _base->object;
+
+#define FOREACH_OBJECT_END \
+ } \
+} ((void)0)
+
+#define FOREACH_OBJECT_FLAG_BEGIN(scene, view_layer, flag, _instance) \
+{ \
+ IteratorBeginCb func_begin; \
+ IteratorCb func_next, func_end; \
+ void *data_in; \
+ \
+ if (flag == SELECT) { \
+ func_begin = &BKE_view_layer_selected_objects_iterator_begin; \
+ func_next = &BKE_view_layer_selected_objects_iterator_next; \
+ func_end = &BKE_view_layer_selected_objects_iterator_end; \
+ data_in = (view_layer); \
+ } \
+ else { \
+ func_begin = BKE_scene_objects_iterator_begin; \
+ func_next = BKE_scene_objects_iterator_next; \
+ func_end = BKE_scene_objects_iterator_end; \
+ data_in = (scene); \
+ } \
+ ITER_BEGIN(func_begin, func_next, func_end, data_in, Object *, _instance)
+
+
+#define FOREACH_OBJECT_FLAG_END \
+ ITER_END; \
+} ((void)0)
+
+struct ObjectsRenderableIteratorData {
+ struct Scene *scene;
+ struct Base base_temp;
+ struct Scene scene_temp;
+
+ struct {
+ struct ViewLayer *view_layer;
+ struct Base *base;
+ struct Scene *set;
+ } iter;
+};
+
+#define FOREACH_OBJECT_RENDERABLE_BEGIN(scene_, _instance) \
+{ \
+ struct ObjectsRenderableIteratorData data_ = { \
+ .scene = (scene_), \
+ }; \
+ ITER_BEGIN(BKE_view_layer_renderable_objects_iterator_begin, \
+ BKE_view_layer_renderable_objects_iterator_next, \
+ BKE_view_layer_renderable_objects_iterator_end, \
+ &data_, Object *, _instance)
+
+
+#define FOREACH_OBJECT_RENDERABLE_END \
+ ITER_END; \
+} ((void)0)
+
+
+/* layer_utils.c */
+
+struct ObjectsInModeParams {
+ int object_mode;
+ uint no_dup_data : 1;
+
+ bool (*filter_fn)(struct Object *ob, void *user_data);
+ void *filter_userdata;
+};
+
+Base **BKE_view_layer_array_from_bases_in_mode_params(
+ struct ViewLayer *view_layer, uint *r_len,
+ const struct ObjectsInModeParams *params);
+
+struct Object **BKE_view_layer_array_from_objects_in_mode_params(
+ struct ViewLayer *view_layer, uint *len,
+ const struct ObjectsInModeParams *params);
+
+#define BKE_view_layer_array_from_objects_in_mode(view_layer, r_len, ...) \
+ BKE_view_layer_array_from_objects_in_mode_params( \
+ view_layer, r_len, \
+ &(const struct ObjectsInModeParams)__VA_ARGS__)
+
+#define BKE_view_layer_array_from_bases_in_mode(view_layer, r_len, ...) \
+ BKE_view_layer_array_from_bases_in_mode_params( \
+ view_layer, r_len, \
+ &(const struct ObjectsInModeParams)__VA_ARGS__)
+
+bool BKE_view_layer_filter_edit_mesh_has_uvs(struct Object *ob, void *user_data);
+bool BKE_view_layer_filter_edit_mesh_has_edges(struct Object *ob, void *user_data);
+
+/* Utility macros that wrap common args (add more as needed). */
+
+#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, r_len) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT});
+
+#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, r_len) \
+ BKE_view_layer_array_from_bases_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT});
+
+#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, r_len) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT, \
+ .no_dup_data = true});
+
+#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, r_len) \
+ BKE_view_layer_array_from_bases_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT, \
+ .no_dup_data = true});
+
+#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, r_len) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = OB_MODE_EDIT, \
+ .no_dup_data = true, \
+ .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs});
+
+#define BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, r_len, mode) \
+ BKE_view_layer_array_from_objects_in_mode( \
+ view_layer, r_len, { \
+ .object_mode = mode, \
+ .no_dup_data = true});
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_LAYER_H__ */
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index c2b971a91cd..038e9377ba4 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -52,9 +52,13 @@ struct PropertyRNA;
size_t BKE_libblock_get_alloc_info(short type, const char **name);
void *BKE_libblock_alloc_notest(short type) ATTR_WARN_UNUSED_RESULT;
-void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name, const int flag) ATTR_WARN_UNUSED_RESULT;
void BKE_libblock_init_empty(struct ID *id) ATTR_NONNULL(1);
+void *BKE_id_new(struct Main *bmain, const short type, const char *name);
+void *BKE_id_new_nomain(const short type, const char *name);
+
+
/**
* New ID creation/copying options.
*/
@@ -75,9 +79,14 @@ enum {
LIB_ID_COPY_NO_PROXY_CLEAR = 1 << 16, /* Object only, needed by make_local code. */
LIB_ID_COPY_NO_PREVIEW = 1 << 17, /* Do not copy preview data, when supported. */
LIB_ID_COPY_CACHES = 1 << 18, /* Copy runtime data caches. */
- /* XXX TODO Do we want to keep that? would rather try to get rid of it... */
- LIB_ID_COPY_ACTIONS = 1 << 19, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */
- LIB_ID_COPY_KEEP_LIB = 1 << 20, /* Keep the library pointer when copying datablock outside of bmain. */
+ LIB_ID_COPY_NO_ANIMDATA = 1 << 19, /* Don't copy id->adt, used by ID datablock localization routines. */
+ LIB_ID_COPY_CD_REFERENCE = 1 << 20, /* Mesh: Reference CD data layers instead of doing real copy. */
+
+ /* XXX Hackish/not-so-nice specific behaviors needed for some corner cases.
+ * Ideally we should not have those, but we need them for now... */
+ LIB_ID_COPY_ACTIONS = 1 << 24, /* EXCEPTION! Deep-copy actions used by animdata of copied ID. */
+ LIB_ID_COPY_KEEP_LIB = 1 << 25, /* Keep the library pointer when copying datablock outside of bmain. */
+ LIB_ID_COPY_SHAPEKEY = 1 << 26, /* EXCEPTION! Deep-copy shapekeys used by copied obdata ID. */
};
void BKE_libblock_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag);
@@ -147,6 +156,7 @@ bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const boo
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
bool id_copy(struct Main *bmain, const struct ID *id, struct ID **newid, bool test);
bool BKE_id_copy_ex(struct Main *bmain, const struct ID *id, struct ID **r_newid, const int flag, const bool test);
+void BKE_id_swap(struct Main *bmain, struct ID *id_a, struct ID *id_b);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
void BKE_id_expand_local(struct Main *bmain, struct ID *id);
void BKE_id_copy_ensure_local(struct Main *bmain, const struct ID *old_id, struct ID *new_id);
@@ -155,28 +165,7 @@ bool new_id(struct ListBase *lb, struct ID *id, const char *name) ATTR_NONNULL(1
void id_clear_lib_data(struct Main *bmain, struct ID *id);
void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_mainlist);
-struct ListBase *which_libbase(struct Main *mainlib, short type);
-
-#define MAX_LIBARRAY 35
-int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
-
-/* Main API */
-struct Main *BKE_main_new(void);
-void BKE_main_free(struct Main *mainvar);
-
-void BKE_main_lock(struct Main *bmain);
-void BKE_main_unlock(struct Main *bmain);
-
-void BKE_main_relations_create(struct Main *bmain);
-void BKE_main_relations_free(struct Main *bmain);
-
-struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
-struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
-void BKE_main_thumbnail_create(struct Main *bmain);
-
-const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL();
-const char *BKE_main_blendfile_path_from_global(void);
-
+/* Affect whole Main database. */
void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const int tag, const bool value);
void BKE_main_id_tag_listbase(struct ListBase *lb, const int tag, const bool value);
void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value);
@@ -188,8 +177,12 @@ void BKE_main_id_clear_newpoins(struct Main *bmain);
void BKE_main_lib_objects_recalc_all(struct Main *bmain);
-/* (MAX_ID_NAME - 2) + 3 */
-void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id);
+#define MAX_ID_FULL_NAME (64 + 64 + 3 + 1) /* 64 is MAX_ID_NAME - 2 */
+#define MAX_ID_FULL_NAME_UI (MAX_ID_FULL_NAME + 3) /* Adds 'keycode' two letters at begining. */
+void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const struct ID *id);
+void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const struct ID *id);
+
+char *BKE_id_to_unique_string_key(const struct ID *id);
void BKE_library_free(struct Library *lib);
@@ -200,7 +193,10 @@ void BKE_library_make_local(
void BKE_id_tag_set_atomic(struct ID *id, int tag);
void BKE_id_tag_clear_atomic(struct ID *id, int tag);
-bool BKE_id_is_in_gobal_main(struct ID *id);
+bool BKE_id_is_in_global_main(struct ID *id);
+
+void BKE_id_ordered_list(struct ListBase *ordered_lb, const struct ListBase *lb);
+void BKE_id_reorder(const struct ListBase *lb, struct ID *id, struct ID *relative, bool after);
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_library_override.h b/source/blender/blenkernel/BKE_library_override.h
new file mode 100644
index 00000000000..b6642bfa726
--- /dev/null
+++ b/source/blender/blenkernel/BKE_library_override.h
@@ -0,0 +1,91 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Bastien Montagne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_LIBRARY_OVERRIDE_H__
+#define __BKE_LIBRARY_OVERRIDE_H__
+
+/** \file BKE_library_override.h
+ * \ingroup bke
+ * \since December 2016
+ * \author mont29
+ */
+
+struct ID;
+struct IDOverrideStatic;
+struct IDOverrideStaticProperty;
+struct IDOverrideStaticPropertyOperation;
+struct Main;
+
+void BKE_override_static_enable(const bool do_enable);
+bool BKE_override_static_is_enabled(void);
+
+struct IDOverrideStatic *BKE_override_static_init(struct ID *local_id, struct ID *reference_id);
+void BKE_override_static_copy(struct ID *dst_id, const struct ID *src_id);
+void BKE_override_static_clear(struct IDOverrideStatic *override);
+void BKE_override_static_free(struct IDOverrideStatic **override);
+
+struct ID *BKE_override_static_create_from_id(struct Main *bmain, struct ID *reference_id);
+bool BKE_override_static_create_from_tag(struct Main *bmain);
+
+struct IDOverrideStaticProperty *BKE_override_static_property_find(struct IDOverrideStatic *override, const char *rna_path);
+struct IDOverrideStaticProperty *BKE_override_static_property_get(struct IDOverrideStatic *override, const char *rna_path, bool *r_created);
+void BKE_override_static_property_delete(struct IDOverrideStatic *override, struct IDOverrideStaticProperty *override_property);
+
+struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find(
+ struct IDOverrideStaticProperty *override_property,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict);
+struct IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get(
+ struct IDOverrideStaticProperty *override_property, const short operation,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex,
+ const bool strict, bool *r_strict, bool *r_created);
+void BKE_override_static_property_operation_delete(
+ struct IDOverrideStaticProperty *override_property, struct IDOverrideStaticPropertyOperation *override_property_operation);
+
+bool BKE_override_static_status_check_local(struct Main *bmain, struct ID *local);
+bool BKE_override_static_status_check_reference(struct Main *bmain, struct ID *local);
+
+bool BKE_override_static_operations_create(struct Main *bmain, struct ID *local, const bool force_auto);
+void BKE_main_override_static_operations_create(struct Main *bmain, const bool force_auto);
+
+void BKE_override_static_update(struct Main *bmain, struct ID *local);
+void BKE_main_override_static_update(struct Main *bmain);
+
+
+/* Storage (.blend file writing) part. */
+
+/* For now, we just use a temp main list. */
+typedef struct Main OverrideStaticStorage;
+
+OverrideStaticStorage *BKE_override_static_operations_store_initialize(void);
+struct ID *BKE_override_static_operations_store_start(
+ struct Main *bmain, OverrideStaticStorage *override_storage, struct ID *local);
+void BKE_override_static_operations_store_end(OverrideStaticStorage *override_storage, struct ID *local);
+void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage);
+
+
+
+#endif /* __BKE_LIBRARY_OVERRIDE_H__ */
diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h
index 65fe9abaa65..dcba5df9a72 100644
--- a/source/blender/blenkernel/BKE_library_query.h
+++ b/source/blender/blenkernel/BKE_library_query.h
@@ -56,6 +56,9 @@ enum {
* How to handle that kind of cases totally depends on what caller code is doing... */
IDWALK_CB_LOOPBACK = (1 << 4),
+ /** That ID is used as static override's reference by its owner. */
+ IDWALK_CB_STATIC_OVERRIDE_REFERENCE = (1 << 5),
+
/**
* Adjusts #ID.us reference-count.
* \note keep in sync with 'newlibadr_us' use in readfile.c
diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h
index fd37fd762f4..3425ca011b7 100644
--- a/source/blender/blenkernel/BKE_library_remap.h
+++ b/source/blender/blenkernel/BKE_library_remap.h
@@ -51,6 +51,8 @@ enum {
* This is needed e.g. in reload scenario, since we have to ensure remapping of Armature data of local proxy
* is also performed. Usual nightmare... */
ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4,
+ /* Do not remap static override pointers. */
+ ID_REMAP_SKIP_STATIC_OVERRIDE = 1 << 5,
};
/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */
diff --git a/source/blender/blenkernel/BKE_bmfont_types.h b/source/blender/blenkernel/BKE_lightprobe.h
index 31513e4b8f1..a769b6653d7 100644
--- a/source/blender/blenkernel/BKE_bmfont_types.h
+++ b/source/blender/blenkernel/BKE_lightprobe.h
@@ -15,7 +15,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * The Original Code is Copyright (C) Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
@@ -24,35 +24,23 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-#ifndef __BKE_BMFONT_TYPES_H__
-#define __BKE_BMFONT_TYPES_H__
-/** \file BKE_bmfont_types.h
+#ifndef __BKE_LIGHTPROBE_H__
+#define __BKE_LIGHTPROBE_H__
+
+/** \file BKE_lightprobe.h
* \ingroup bke
- * \since March 2001
- * \author nzc
- */
-#define is_power_of_two(N) ((N ^ (N - 1)) == (2 * N - 1))
-/*
- * Moved to IMB_imbuf_types.h where it will live close to the ImBuf type.
- * It is used as a userflag bit mask.
+ * \brief General operations for probes.
*/
-// #define IB_BITMAPFONT 1
-typedef struct bmGlyph {
- unsigned short unicode;
- short locx, locy;
- signed char ofsx, ofsy;
- unsigned char sizex, sizey;
- unsigned char advance, reserved;
-} bmGlyph;
+struct Main;
+struct LightProbe;
-typedef struct bmFont {
- char magic[4];
- short version;
- short glyphcount;
- short xsize, ysize;
- bmGlyph glyphs[1];
-} bmFont;
+void BKE_lightprobe_init(struct LightProbe *probe);
+void *BKE_lightprobe_add(struct Main *bmain, const char *name);
+void BKE_lightprobe_copy_data(struct Main *bmain, struct LightProbe *probe_dst, const struct LightProbe *probe_src, const int flag);
+struct LightProbe *BKE_lightprobe_copy(struct Main *bmain, const struct LightProbe *probe);
+void BKE_lightprobe_make_local(struct Main *bmain, struct LightProbe *probe, const bool lib_local);
+void BKE_lightprobe_free(struct LightProbe *probe);
-#endif
+#endif /* __BKE_LIGHTPROBE_H__ */
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index 3ba4fbe0338..376a324d25c 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -48,6 +48,7 @@ struct Main;
struct Object;
struct ColorBand;
struct bContext;
+struct ViewLayer;
void BKE_linestyle_init(struct FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
@@ -59,7 +60,7 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, const FreestyleLineSt
void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local);
-FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene);
+FreestyleLineStyle *BKE_linestyle_active_from_view_layer(struct ViewLayer *view_layer);
LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index e224155726f..e5a816b92ce 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -42,17 +42,20 @@
*/
#include "DNA_listBase.h"
-#include "BKE_library.h"
+#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
#ifdef __cplusplus
extern "C" {
#endif
-struct EvaluationContext;
+struct BlendThumbnail;
+struct BLI_mempool;
+struct Depsgraph;
+struct GHash;
+struct ImBuf;
struct Library;
struct MainLock;
-struct GHash;
-struct BLI_mempool;
/* Blender thumbnail, as written on file (width, height, and data as char RGBA). */
/* We pack pixel data after that struct. */
@@ -110,8 +113,9 @@ typedef struct Main {
ListBase vfont;
ListBase text;
ListBase speaker;
+ ListBase lightprobe;
ListBase sound;
- ListBase group;
+ ListBase collection;
ListBase armature;
ListBase action;
ListBase nodetree;
@@ -125,11 +129,7 @@ typedef struct Main {
ListBase mask;
ListBase linestyle;
ListBase cachefiles;
-
- char id_tag_update[MAX_LIBARRAY];
-
- /* Evaluation context used by viewport */
- struct EvaluationContext *eval_ctx;
+ ListBase workspaces;
/* Must be generated, used and freed by same code - never assume this is valid data unless you know
* when, who and how it was created.
@@ -139,6 +139,27 @@ typedef struct Main {
struct MainLock *lock;
} Main;
+struct Main *BKE_main_new(void);
+void BKE_main_free(struct Main *mainvar);
+
+void BKE_main_lock(struct Main *bmain);
+void BKE_main_unlock(struct Main *bmain);
+
+void BKE_main_relations_create(struct Main *bmain);
+void BKE_main_relations_free(struct Main *bmain);
+
+struct BlendThumbnail *BKE_main_thumbnail_from_imbuf(struct Main *bmain, struct ImBuf *img);
+struct ImBuf *BKE_main_thumbnail_to_imbuf(struct Main *bmain, struct BlendThumbnail *data);
+void BKE_main_thumbnail_create(struct Main *bmain);
+
+const char *BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL();
+const char *BKE_main_blendfile_path_from_global(void);
+
+struct ListBase *which_libbase(struct Main *mainlib, short type);
+
+#define MAX_LIBARRAY 37
+int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
+
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
((main)->versionfile > (ver) || (main->versionfile == (ver) && (main)->subversionfile >= (subver)))
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 5598f0dc473..976ee5b2691 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -32,7 +32,7 @@
* \ingroup bke
*/
-struct EvaluationContext;
+struct Depsgraph;
struct ImageUser;
struct Image;
struct ListBase;
@@ -145,7 +145,6 @@ void BKE_mask_update_display(struct Mask *mask, float ctime);
void BKE_mask_evaluate_all_masks(struct Main *bmain, float ctime, const bool do_newframe);
void BKE_mask_evaluate(struct Mask *mask, const float ctime, const bool do_newframe);
void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const bool do_newframe);
-void BKE_mask_update_scene(struct Main *bmain, struct Scene *scene);
void BKE_mask_parent_init(struct MaskParent *parent);
void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline, struct MaskSplinePoint *point, const float u);
void BKE_mask_calc_tangent_polyline(struct MaskSpline *spline, struct MaskSplinePoint *point, float t[2]);
@@ -237,8 +236,8 @@ float *BKE_mask_point_segment_feather_diff(struct MaskSpline *spline, struct Mas
void BKE_mask_layer_evaluate_animation(struct MaskLayer *masklay, const float ctime);
void BKE_mask_layer_evaluate_deform(struct MaskLayer *masklay, const float ctime);
-void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, struct Mask *mask);
-void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, struct Mask *mask);
+void BKE_mask_eval_animation(struct Depsgraph *depsgraph, struct Mask *mask);
+void BKE_mask_eval_update(struct Depsgraph *depsgraph, struct Mask *mask);
/* mask_rasterize.c */
struct MaskRasterHandle;
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index e2f5fb23465..1ca8928c61d 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -54,11 +54,13 @@ void BKE_material_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
+struct Material *BKE_material_add_gpencil(struct Main *bmain, const char *name);
void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag);
struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma);
struct Material *BKE_material_localize(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local);
+void BKE_material_init_gpencil_settings(struct Material *ma);
/* UNUSED */
// void automatname(struct Material *);
@@ -87,6 +89,8 @@ short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma
bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
+struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);
+
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
@@ -97,26 +101,19 @@ struct Material *BKE_material_pop_id(struct Main *bmain, struct ID *id, int inde
void BKE_material_clear_id(struct Main *bmain, struct ID *id, bool update_data);
/* rendering */
-void init_render_material(struct Main *bmain, struct Material *, int, float *);
-void init_render_materials(struct Main *, int r_mode, float *amd, bool do_default_material);
-void end_render_material(struct Material *);
-void end_render_materials(struct Main *);
-
-bool material_in_material(struct Material *parmat, struct Material *mat);
-
void ramp_blend(int type, float r_col[3], const float fac, const float col[3]);
-/* driver update hacks */
-void material_drivers_update(struct Scene *scene, struct Material *mat, float ctime);
-
/* copy/paste */
void clear_matcopybuf(void);
void free_matcopybuf(void);
void copy_matcopybuf(struct Main *bmain, struct Material *ma);
void paste_matcopybuf(struct Main *bmain, struct Material *ma);
-/* handle backward compatibility for tface/materials called from doversion */
-int do_version_tface(struct Main *main);
+/* Evaluation. */
+
+struct Depsgraph;
+
+void BKE_material_eval(struct Depsgraph *depsgraph, struct Material *material);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 87bc7b2dfc5..a7706915bc5 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -32,7 +32,8 @@
* \since March 2001
* \author nzc
*/
-struct EvaluationContext;
+struct BoundBox;
+struct Depsgraph;
struct Main;
struct MetaBall;
struct Object;
@@ -47,36 +48,49 @@ struct MetaBall *BKE_mball_copy(struct Main *bmain, const struct MetaBall *mb);
void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool lib_local);
+bool BKE_mball_is_any_selected(const struct MetaBall *mb);
+bool BKE_mball_is_any_selected_multi(struct Object **objects, int objects_len);
+bool BKE_mball_is_any_unselected(const struct MetaBall *mb);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
bool BKE_mball_is_basis(struct Object *ob);
-struct Object *BKE_mball_basis_find(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
+struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob);
void BKE_mball_texspace_calc(struct Object *ob);
+struct BoundBox *BKE_mball_boundbox_get(struct Object *ob);
float *BKE_mball_make_orco(struct Object *ob, struct ListBase *dispbase);
-void BKE_mball_properties_copy(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *active_object);
+void BKE_mball_properties_copy(struct Scene *scene, struct Object *active_object);
-bool BKE_mball_minmax(struct MetaBall *mb, float min[3], float max[3]);
-bool BKE_mball_minmax_ex(struct MetaBall *mb, float min[3], float max[3],
- float obmat[4][4], const short flag);
-bool BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]);
-bool BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]);
+bool BKE_mball_minmax_ex(
+ const struct MetaBall *mb, float min[3], float max[3],
+ const float obmat[4][4], const short flag);
+bool BKE_mball_minmax(const struct MetaBall *mb, float min[3], float max[3]);
+bool BKE_mball_center_median(const struct MetaBall *mb, float r_cent[3]);
+bool BKE_mball_center_bounds(const struct MetaBall *mb, float r_cent[3]);
void BKE_mball_transform(struct MetaBall *mb, float mat[4][4], const bool do_props);
void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type);
+int BKE_mball_select_count(const struct MetaBall *mb);
+int BKE_mball_select_count_multi(struct Object **objects, int objects_len);
void BKE_mball_select_all(struct MetaBall *mb);
+void BKE_mball_select_all_multi(struct Object **objects, int objects_len);
void BKE_mball_deselect_all(struct MetaBall *mb);
+void BKE_mball_deselect_all_multi(struct Object **objects, int objects_len);
void BKE_mball_select_swap(struct MetaBall *mb);
+void BKE_mball_select_swap_multi(struct Object **objects, int objects_len);
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
+struct Depsgraph;
-void BKE_mball_eval_geometry(struct EvaluationContext *eval_ctx,
- struct MetaBall *mball);
+/* Draw Cache */
+
+enum {
+ BKE_MBALL_BATCH_DIRTY_ALL = 0,
+};
+void BKE_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode);
+void BKE_mball_batch_cache_free(struct MetaBall *mb);
#endif
diff --git a/source/blender/blenkernel/BKE_mball_tessellate.h b/source/blender/blenkernel/BKE_mball_tessellate.h
index 254d5e9248a..363bfe09c75 100644
--- a/source/blender/blenkernel/BKE_mball_tessellate.h
+++ b/source/blender/blenkernel/BKE_mball_tessellate.h
@@ -23,13 +23,13 @@
/** \file BKE_mball_tessellate.h
* \ingroup bke
*/
-struct EvaluationContext;
+struct Depsgraph;
struct Main;
struct Object;
struct Scene;
void BKE_mball_polygonize(
- struct Main *bmain, struct EvaluationContext *eval_ctx, struct Scene *scene,
+ struct Depsgraph *depsgraph, struct Scene *scene,
struct Object *ob, struct ListBase *dispbase);
void BKE_mball_cubeTable_free(void);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 6d2a431f667..8f0c81ce4f9 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -31,31 +31,43 @@
* \ingroup bke
*/
+/* defines BLI_INLINE */
+#include "BLI_compiler_compat.h"
+
+/* defines CustomDataMask */
+#include "BKE_customdata.h"
+
struct ID;
struct BMeshCreateParams;
+struct BMeshFromMeshParams;
+struct BMeshToMeshParams;
struct BoundBox;
+struct Depsgraph;
struct EdgeHash;
struct ListBase;
struct LinkNode;
struct BLI_Stack;
struct MemArena;
struct BMesh;
+struct KeyBlock;
struct MLoopTri;
struct Main;
struct Mesh;
+struct ModifierData;
struct MPoly;
struct MLoop;
struct MFace;
struct MEdge;
struct MVert;
+struct MVertTri;
struct MDeformVert;
struct MDisps;
struct Object;
struct CustomData;
-struct DerivedMesh;
struct Scene;
struct MLoopUV;
struct ReportList;
+struct BMEditMesh;
#ifdef __cplusplus
extern "C" {
@@ -70,10 +82,20 @@ extern "C" {
/* *** mesh.c *** */
+struct BMesh *BKE_mesh_to_bmesh_ex(
+ struct Mesh *me,
+ const struct BMeshCreateParams *create_params,
+ const struct BMeshFromMeshParams *convert_params);
struct BMesh *BKE_mesh_to_bmesh(
struct Mesh *me, struct Object *ob,
const bool add_key_index, const struct BMeshCreateParams *params);
+struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm, const struct BMeshToMeshParams *params);
+struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, int64_t cd_mask_extra);
+
+struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ struct BMEditMesh *em, CustomDataMask data_mask, float (*vertexCos)[3]);
+
int poly_find_loop_from_vert(
const struct MPoly *poly,
const struct MLoop *loopstart, unsigned vert);
@@ -83,6 +105,7 @@ int poly_get_adj_loops_from_vert(
unsigned int r_adj[2]);
int BKE_mesh_edge_other_vert(const struct MEdge *e, int v);
+void BKE_mesh_looptri_get_real_edges(const struct Mesh *mesh, const struct MLoopTri *looptri, int r_edges[3]);
void BKE_mesh_free(struct Mesh *me);
void BKE_mesh_init(struct Mesh *me);
@@ -92,6 +115,24 @@ struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);
+struct Mesh *BKE_mesh_new_nomain(
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len);
+struct Mesh *BKE_mesh_new_nomain_from_template(
+ const struct Mesh *me_src,
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len);
+
+/* Performs copy for use during evaluation, optional referencing original arrays to reduce memory. */
+struct Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference);
+
+/* These functions construct a new Mesh, contrary to BKE_mesh_from_nurbs which modifies ob itself. */
+struct Mesh *BKE_mesh_new_nomain_from_curve(struct Object *ob);
+struct Mesh *BKE_mesh_new_nomain_from_curve_displist(struct Object *ob, struct ListBase *dispbase);
+
+bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me);
+bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
+
void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool lib_local);
void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]);
void BKE_mesh_texspace_calc(struct Mesh *me);
@@ -100,6 +141,22 @@ void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totv
int test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr);
struct Mesh *BKE_mesh_from_object(struct Object *ob);
void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me);
+void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
+int BKE_mesh_nurbs_to_mdata(
+ struct Object *ob, struct MVert **r_allvert, int *r_totvert,
+ struct MEdge **r_alledge, int *r_totedge, struct MLoop **r_allloop, struct MPoly **r_allpoly,
+ int *r_totloop, int *r_totpoly);
+int BKE_mesh_nurbs_displist_to_mdata(
+ struct Object *ob, const struct ListBase *dispbase,
+ struct MVert **r_allvert, int *r_totvert,
+ struct MEdge **r_alledge, int *r_totedge,
+ struct MLoop **r_allloop, struct MPoly **r_allpoly,
+ struct MLoopUV **r_alluv, int *r_totloop, int *r_totpoly);
+void BKE_mesh_from_nurbs_displist(
+ struct Main *bmain, struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary);
+void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob);
+void BKE_mesh_to_curve_nurblist(const struct Mesh *me, struct ListBase *nurblist, const int edge_users_test);
+void BKE_mesh_to_curve(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_mesh_material_index_remove(struct Mesh *me, short index);
void BKE_mesh_material_index_clear(struct Mesh *me);
void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
@@ -109,16 +166,31 @@ 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,
- const char *new_name, const bool do_tessface);
+bool BKE_mesh_uv_cdlayer_rename_index(
+ struct Mesh *me, const int loop_index, const int face_index,
+ const char *new_name, const bool do_tessface);
bool BKE_mesh_uv_cdlayer_rename(struct Mesh *me, const char *old_name, const char *new_name, bool do_tessface);
float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3];
void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals);
+struct Mesh *BKE_mesh_new_from_object(
+ struct Depsgraph *depsgraph, struct Main *bmain, struct Scene *sce, struct Object *ob,
+ const bool apply_modifiers, const bool calc_undeformed);
+struct Mesh *BKE_mesh_create_derived_for_modifier(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ struct ModifierData *md, int build_shapekey_layers);
+
+/* Copies a nomain-Mesh into an existing Mesh. */
+void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob,
+ CustomDataMask mask, bool take_ownership);
+void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct KeyBlock *kb);
+
+
/* vertex level transformations & checks (no derived mesh) */
bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]);
@@ -140,31 +212,13 @@ int BKE_mesh_mselect_find(struct Mesh *me, int index, int type);
int BKE_mesh_mselect_active_get(struct Mesh *me, int type);
void BKE_mesh_mselect_active_set(struct Mesh *me, int index, int type);
-/* *** mesh_convert.c *** */
+void BKE_mesh_apply_vert_coords(struct Mesh *mesh, float (*vertCoords)[3]);
+void BKE_mesh_apply_vert_normals(struct Mesh *mesh, short (*vertNormals)[3]);
-void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
-int BKE_mesh_nurbs_to_mdata(
- struct Object *ob, struct MVert **r_allvert, int *r_totvert,
- struct MEdge **r_alledge, int *r_totedge, struct MLoop **r_allloop, struct MPoly **r_allpoly,
- int *r_totloop, int *r_totpoly);
-int BKE_mesh_nurbs_displist_to_mdata(
- struct Object *ob, const struct ListBase *dispbase,
- struct MVert **r_allvert, int *r_totvert,
- struct MEdge **r_alledge, int *r_totedge,
- struct MLoop **r_allloop, struct MPoly **r_allpoly,
- struct MLoopUV **r_alluv, int *r_totloop, int *r_totpoly);
-void BKE_mesh_from_nurbs_displist(
- struct Main *bmain, struct Object *ob, struct ListBase *dispbase, const bool use_orco_uv, const char *obdata_name);
-void BKE_mesh_from_nurbs(struct Main *bmain, struct Object *ob);
-void BKE_mesh_to_curve_nurblist(struct DerivedMesh *dm, struct ListBase *nurblist, const int edge_users_test);
-void BKE_mesh_to_curve(struct Main *bmain, struct Scene *scene, struct Object *ob);
-
-struct Mesh *BKE_mesh_new_from_object(
- struct Main *bmain, struct Scene *sce, struct Object *ob,
- int apply_modifiers, int settings, int calc_tessface, int calc_undeformed);
/* *** mesh_evaluate.c *** */
+void BKE_mesh_calc_normals_mapping_simple(struct Mesh *me);
void BKE_mesh_calc_normals_mapping(
struct MVert *mverts, int numVerts,
const struct MLoop *mloop, const struct MPoly *mpolys, int numLoops, int numPolys, float (*r_polyNors)[3],
@@ -181,6 +235,8 @@ void BKE_mesh_calc_normals_poly(
int numLoops, int numPolys, float (*r_polyNors)[3],
const bool only_face_normals);
void BKE_mesh_calc_normals(struct Mesh *me);
+void BKE_mesh_ensure_normals(struct Mesh *me);
+void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
void BKE_mesh_calc_normals_tessface(
struct MVert *mverts, int numVerts,
const struct MFace *mfaces, int numFaces,
@@ -190,13 +246,6 @@ void BKE_mesh_calc_normals_looptri(
const struct MLoop *mloop,
const struct MLoopTri *looptri, int looptri_num,
float (*r_tri_nors)[3]);
-void BKE_mesh_loop_tangents_ex(
- const struct MVert *mverts, const int numVerts, const struct MLoop *mloops,
- float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv,
- const int numLoops, const struct MPoly *mpolys, const int numPolys,
- struct ReportList *reports);
-void BKE_mesh_loop_tangents(
- struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
void BKE_mesh_loop_manifold_fan_around_vert_next(
const struct MLoop *mloops, const struct MPoly *mpolys,
const int *loop_to_poly, const int *e2lfan_curr, const uint mv_pivot_index,
@@ -224,6 +273,8 @@ typedef struct MLoopNorSpace {
* - BMLoop pointers. */
struct LinkNode *loops;
char flags;
+
+ void *user_data; /* To be used for extended processing related to loop normal spaces (aka smooth fans). */
} MLoopNorSpace;
/**
* MLoopNorSpace.flags
@@ -239,6 +290,7 @@ typedef struct MLoopNorSpaceArray {
MLoopNorSpace **lspacearr; /* MLoop aligned array */
struct LinkNode *loops_pool; /* Allocated once, avoids to call BLI_linklist_prepend_arena() for each loop! */
char data_type; /* Whether we store loop indices, or pointers to BMLoop. */
+ int num_spaces; /* Number of clnors spaces defined in this array. */
struct MemArena *mem;
} MLoopNorSpaceArray;
/**
@@ -332,7 +384,7 @@ void BKE_mesh_loops_to_mface_corners(
const int numTex, const int numCol,
const bool hasPCol, const bool hasOrigSpace, const bool hasLNor);
void BKE_mesh_loops_to_tessdata(
- struct CustomData *fdata, struct CustomData *ldata, struct CustomData *pdata, struct MFace *mface,
+ struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces);
void BKE_mesh_tangent_loops_to_tessdata(
struct CustomData *fdata, struct CustomData *ldata, struct MFace *mface,
@@ -365,6 +417,19 @@ void BKE_mesh_polygon_flip_ex(
void BKE_mesh_polygon_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata);
void BKE_mesh_polygons_flip(struct MPoly *mpoly, struct MLoop *mloop, struct CustomData *ldata, int totpoly);
+/* merge verts */
+/* Enum for merge_mode of CDDM_merge_verts.
+ * Refer to mesh.c for details. */
+enum {
+ MESH_MERGE_VERTS_DUMP_IF_MAPPED,
+ MESH_MERGE_VERTS_DUMP_IF_EQUAL,
+};
+struct Mesh *BKE_mesh_merge_verts(
+ struct Mesh *mesh,
+ const int *vtargetmap, const int tot_vtargetmap,
+ const int merge_mode);
+
+
/* flush flags */
void BKE_mesh_flush_hidden_from_verts_ex(
const struct MVert *mvert,
@@ -407,7 +472,7 @@ void BKE_mesh_calc_relative_deform(
/* *** mesh_validate.c *** */
bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask);
-void BKE_mesh_cd_validate(struct Mesh *me);
+bool BKE_mesh_is_valid(struct Mesh *me);
bool BKE_mesh_validate_material_indices(struct Mesh *me);
bool BKE_mesh_validate_arrays(
@@ -433,15 +498,41 @@ void BKE_mesh_strip_loose_polysloops(struct Mesh *me);
void BKE_mesh_strip_loose_edges(struct Mesh *me);
void BKE_mesh_calc_edges_legacy(struct Mesh *me, const bool use_old);
+void BKE_mesh_calc_edges_loose(struct Mesh *mesh);
void BKE_mesh_calc_edges(struct Mesh *mesh, bool update, const bool select);
+void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
-
-void BKE_mesh_eval_geometry(struct EvaluationContext *eval_ctx,
+void BKE_mesh_eval_geometry(struct Depsgraph *depsgraph,
struct Mesh *mesh);
+/* Draw Cache */
+enum {
+ BKE_MESH_BATCH_DIRTY_ALL = 0,
+ BKE_MESH_BATCH_DIRTY_MAYBE_ALL,
+ BKE_MESH_BATCH_DIRTY_SELECT,
+ BKE_MESH_BATCH_DIRTY_SHADING,
+ BKE_MESH_BATCH_DIRTY_SCULPT_COORDS,
+ BKE_MESH_BATCH_DIRTY_UVEDIT_ALL,
+ BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT,
+};
+void BKE_mesh_batch_cache_dirty_tag(struct Mesh *me, int mode);
+void BKE_mesh_batch_cache_free(struct Mesh *me);
+
+
+/* Inlines */
+
+/* Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h,
+ * but I don't want to force every user of BKE_mesh.h to also include that file.
+ * ~~ Sybren */
+BLI_INLINE int BKE_mesh_origindex_mface_mpoly(
+ const int *index_mf_to_mpoly, const int *index_mp_to_orig, const int i)
+{
+ const int j = index_mf_to_mpoly[i];
+ return (j != -1) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : -1;
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h
new file mode 100644
index 00000000000..70c10806350
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_iterators.h
@@ -0,0 +1,67 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MESH_ITERATORS_H__
+#define __BKE_MESH_ITERATORS_H__
+
+/** \file BKE_mesh_iterators.h
+ * \ingroup bke
+ */
+
+struct Mesh;
+struct MVert;
+struct MEdge;
+struct MPoly;
+struct MLoop;
+struct MLoopUV;
+struct MLoopTri;
+
+typedef enum MeshForeachFlag {
+ MESH_FOREACH_NOP = 0,
+ MESH_FOREACH_USE_NORMAL = (1 << 0), /* foreachMappedVert, foreachMappedLoop, foreachMappedFaceCenter */
+} MeshForeachFlag;
+
+
+void BKE_mesh_foreach_mapped_vert(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
+ void *userData,
+ MeshForeachFlag flag);
+void BKE_mesh_foreach_mapped_edge(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
+ void *userData);
+void BKE_mesh_foreach_mapped_loop(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag);
+void BKE_mesh_foreach_mapped_face_center(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int index, const float cent[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag);
+
+void BKE_mesh_foreach_mapped_vert_coords_get(struct Mesh *me_eval, float (*r_cos)[3], const int totcos);
+
+#endif /* __BKE_MESH_ITERATORS_H__ */
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index 5c77ab8a94e..7aea856ff34 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -26,7 +26,7 @@
*/
struct CustomData;
-struct DerivedMesh;
+struct Mesh;
struct MVert;
struct MemArena;
@@ -140,39 +140,37 @@ enum {
MREMAP_MODE_TOPOLOGY = MREMAP_MODE_VERT | MREMAP_MODE_EDGE | MREMAP_MODE_LOOP | MREMAP_MODE_POLY,
};
-float BKE_mesh_remap_calc_difference_from_dm(
+float BKE_mesh_remap_calc_difference_from_mesh(
const struct SpaceTransform *space_transform,
- const struct MVert *verts_dst, const int numverts_dst, struct DerivedMesh *dm_src);
+ const struct MVert *verts_dst, const int numverts_dst, struct Mesh *me_src);
-void BKE_mesh_remap_find_best_match_from_dm(
- const struct MVert *verts_dst, const int numverts_dst, struct DerivedMesh *dm_src,
+void BKE_mesh_remap_find_best_match_from_mesh(
+ const struct MVert *verts_dst, const int numverts_dst, struct Mesh *me_src,
struct SpaceTransform *r_space_transform);
-/* TODO add mesh2mesh versions (we'll need mesh versions of bvhtree funcs too, though!). */
-
-void BKE_mesh_remap_calc_verts_from_dm(
+void BKE_mesh_remap_calc_verts_from_mesh(
const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius,
const struct MVert *verts_dst, const int numverts_dst, const bool dirty_nors_dst,
- struct DerivedMesh *dm_src, MeshPairRemap *r_map);
+ struct Mesh *me_src, MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_edges_from_dm(
+void BKE_mesh_remap_calc_edges_from_mesh(
const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius,
const struct MVert *verts_dst, const int numverts_dst, const struct MEdge *edges_dst, const int numedges_dst,
- const bool dirty_nors_dst, struct DerivedMesh *dm_src, MeshPairRemap *r_map);
+ const bool dirty_nors_dst, struct Mesh *me_src, MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_loops_from_dm(
+void BKE_mesh_remap_calc_loops_from_mesh(
const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius,
struct MVert *verts_dst, const int numverts_dst, struct MEdge *edges_dst, const int numedges_dst,
struct MLoop *loops_dst, const int numloops_dst, struct MPoly *polys_dst, const int numpolys_dst,
struct CustomData *ldata_dst, struct CustomData *pdata_dst,
const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
- struct DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src,
+ struct Mesh *me_src,
MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, struct MeshPairRemap *r_map);
-void BKE_mesh_remap_calc_polys_from_dm(
+void BKE_mesh_remap_calc_polys_from_mesh(
const int mode, const struct SpaceTransform *space_transform, const float max_dist, const float ray_radius,
struct MVert *verts_dst, const int numverts_dst, struct MLoop *loops_dst, const int numloops_dst,
struct MPoly *polys_dst, const int numpolys_dst, struct CustomData *pdata_dst, const bool dirty_nors_dst,
- struct DerivedMesh *dm_src, struct MeshPairRemap *r_map);
+ struct Mesh *me_src, struct MeshPairRemap *r_map);
#endif /* __BKE_MESH_REMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
new file mode 100644
index 00000000000..050d17771c9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -0,0 +1,122 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MESH_RUNTIME_H__
+#define __BKE_MESH_RUNTIME_H__
+
+/** \file BKE_mesh_runtime.h
+ * \ingroup bke
+ *
+ * This file contains access functions for the Mesh.runtime struct.
+ */
+
+#include "BKE_customdata.h" /* for CustomDataMask */
+
+struct ColorBand;
+struct CustomData;
+struct Depsgraph;
+struct KeyBlock;
+struct Mesh;
+struct MLoop;
+struct MLoopTri;
+struct MVertTri;
+struct Object;
+struct Scene;
+
+/* Undefine to hide DerivedMesh-based function declarations */
+#define USE_DERIVEDMESH
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh;
+#endif
+
+void BKE_mesh_runtime_reset(struct Mesh *mesh);
+int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh);
+void BKE_mesh_runtime_looptri_recalc(struct Mesh *mesh);
+const struct MLoopTri *BKE_mesh_runtime_looptri_ensure(struct Mesh *mesh);
+bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh);
+bool BKE_mesh_runtime_clear_edit_data(struct Mesh *mesh);
+void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh);
+void BKE_mesh_runtime_clear_cache(struct Mesh *mesh);
+
+void BKE_mesh_runtime_verttri_from_looptri(
+ struct MVertTri *r_verttri,
+ const struct MLoop *mloop, const struct MLoopTri *looptri, int looptri_num);
+
+/* NOTE: the functions below are defined in DerivedMesh.c, and are intended to be moved
+ * to a more suitable location when that file is removed.
+ * They should also be renamed to use conventions from BKE, not old DerivedMesh.c.
+ * For now keep the names similar to avoid confusion. */
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_get_derived_final(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+#endif
+struct Mesh *mesh_get_eval_final(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, CustomDataMask dataMask);
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_get_derived_deform(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+#endif
+struct Mesh *mesh_get_eval_deform(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+
+struct Mesh *mesh_create_eval_final_render(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_create_derived_index_render(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask, int index);
+#endif
+struct Mesh *mesh_create_eval_final_index_render(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask, int index);
+
+#ifdef USE_DERIVEDMESH
+struct DerivedMesh *mesh_create_derived_view(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+#endif
+struct Mesh *mesh_create_eval_final_view(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask);
+
+void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed, struct Mesh *me, struct KeyBlock *kb);
+
+
+#ifndef NDEBUG
+char *BKE_mesh_runtime_debug_info(struct Mesh *me_eval);
+void BKE_mesh_runtime_debug_print(struct Mesh *me_eval);
+void BKE_mesh_runtime_debug_print_cdlayers(struct CustomData *data);
+bool BKE_mesh_runtime_is_valid(struct Mesh *me_eval);
+#endif /* NDEBUG */
+
+#endif /* __BKE_MESH_RUNTIME_H__ */
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
new file mode 100644
index 00000000000..62d8f3ada84
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_tangent.h
@@ -0,0 +1,68 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_MESH_TANGENT_H__
+#define __BKE_MESH_TANGENT_H__
+
+/** \file BKE_mesh_tangent.h
+ * \ingroup bke
+ */
+
+void BKE_mesh_calc_loop_tangent_single_ex(
+ const struct MVert *mverts, const int numVerts, const struct MLoop *mloops,
+ float (*r_looptangent)[4], float (*loopnors)[3], const struct MLoopUV *loopuv,
+ const int numLoops, const struct MPoly *mpolys, const int numPolys,
+ struct ReportList *reports);
+void BKE_mesh_calc_loop_tangent_single(
+ struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
+
+void BKE_mesh_calc_loop_tangent_ex(
+ const struct MVert *mvert,
+ const struct MPoly *mpoly, const uint mpoly_len,
+ const struct MLoop *mloop,
+ const struct MLoopTri *looptri, const uint looptri_len,
+
+ struct CustomData *loopdata,
+ bool calc_active_tangent,
+ const char (*tangent_names)[64], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ struct CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p);
+
+void BKE_mesh_calc_loop_tangents(
+ struct Mesh *me_eval, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len);
+
+/* Helpers */
+void BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ struct CustomData *uv_data, struct CustomData *tan_data, int numLoopData,
+ const char *layer_name);
+
+#define DM_TANGENT_MASK_ORCO (1 << 9)
+void BKE_mesh_calc_loop_tangent_step_0(
+ const struct CustomData *loopData, bool calc_active_tangent,
+ const char (*tangent_names)[64], int tangent_names_count,
+ bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+ char *ract_uv_name, char *rren_uv_name, short *rtangent_mask);
+
+#endif /* __BKE_MESH_TANGENT_H__ */
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 2d39ac4d102..6b64b1663d8 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -33,11 +33,12 @@
#include "BKE_customdata.h"
struct ID;
+struct Depsgraph;
struct DerivedMesh;
-struct DagForest;
-struct DagNode;
+struct Mesh;
struct Object;
struct Scene;
+struct ViewLayer;
struct ListBase;
struct bArmature;
struct Main;
@@ -118,27 +119,23 @@ typedef enum ModifierApplyFlag {
MOD_APPLY_IGNORE_SIMPLIFY = 1 << 3, /* Ignore scene simplification flag and use subdivisions
* level set in multires modifier.
*/
- MOD_APPLY_ALLOW_GPU = 1 << 4, /* Allow modifier to be applied and stored in the GPU.
- * Used by the viewport in order to be able to have SS
- * happening on GPU.
- * Render pipeline (including viewport render) should
- * have DM on the CPU.
- */
} ModifierApplyFlag;
-
typedef struct ModifierUpdateDepsgraphContext {
struct Scene *scene;
struct Object *object;
-
- /* Old depsgraph node handle. */
- struct DagForest *forest;
- struct DagNode *obNode;
-
- /* new depsgraph node handle. */
struct DepsNodeHandle *node;
} ModifierUpdateDepsgraphContext;
+/* Contains the information for deformXXX and applyXXX functions below that
+ * doesn't change between consecutive modifiers. */
+typedef struct ModifierEvalContext {
+ struct Depsgraph *depsgraph;
+ struct Object *object;
+ ModifierApplyFlag flag;
+} ModifierEvalContext;
+
+
typedef struct ModifierTypeInfo {
/* The user visible name for this modifier */
char name[32];
@@ -159,73 +156,61 @@ typedef struct ModifierTypeInfo {
/* Copy instance data for this modifier type. Should copy all user
* level settings to the target modifier.
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
- void (*copyData)(const struct ModifierData *md, struct ModifierData *target);
+ void (*copyData)(const struct ModifierData *md, struct ModifierData *target, const int flag);
+
+
+ /********************* Deform modifier functions *********************/ /* DEPRECATED */
+
+ void (*deformVerts_DM_removed)(void);
+ void (*deformMatrices_DM_removed)(void);
+ void (*deformVertsEM_DM_removed)(void);
+ void (*deformMatricesEM_DM_removed)(void);
+
+ /********************* Non-deform modifier functions *********************/ /* DEPRECATED */
+
+ void (*applyModifier_DM_removed)(void);
/********************* Deform modifier functions *********************/
/* Only for deform types, should apply the deformation
* to the given vertex array. If the deformer requires information from
- * the object it can obtain it from the derivedData argument if non-NULL,
+ * the object it can obtain it from the mesh argument if non-NULL,
* and otherwise the ob argument.
*/
- void (*deformVerts)(struct ModifierData *md, struct Object *ob,
- struct DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts,
- ModifierApplyFlag flag);
+ void (*deformVerts)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
/* Like deformMatricesEM but called from object mode (for supporting modifiers in sculpt mode) */
- void (*deformMatrices)(struct ModifierData *md, struct Object *ob,
- struct DerivedMesh *derivedData,
- float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
+ void (*deformMatrices)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
/* Like deformVerts but called during editmode (for supporting modifiers)
*/
- void (*deformVertsEM)(struct ModifierData *md, struct Object *ob,
- struct BMEditMesh *editData, struct DerivedMesh *derivedData,
- float (*vertexCos)[3], int numVerts);
+ void (*deformVertsEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ struct Mesh *mesh, float (*vertexCos)[3], int numVerts);
/* Set deform matrix per vertex for crazyspace correction */
- void (*deformMatricesEM)(struct ModifierData *md, struct Object *ob,
- struct BMEditMesh *editData, struct DerivedMesh *derivedData,
- float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
+ void (*deformMatricesEM)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct BMEditMesh *editData,
+ struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
/********************* Non-deform modifier functions *********************/
- /* For non-deform types: apply the modifier and return a derived
- * data object (type is dependent on object type).
+ /* For non-deform types: apply the modifier and return a mesh object.
*
- * The derivedData argument should always be non-NULL; the modifier
- * should read the object data from the derived object instead of the
+ * The mesh argument should always be non-NULL; the modifier
+ * should read the object data from the mesh object instead of the
* actual object data.
*
- * The useRenderParams argument indicates if the modifier is being
- * applied in the service of the renderer which may alter quality
- * settings.
- *
- * The isFinalCalc parameter indicates if the modifier is being
- * calculated for a final result or for something temporary
- * (like orcos). This is a hack at the moment, it is meant so subsurf
- * can know if it is safe to reuse its internal cache.
- *
- * The modifier may reuse the derivedData argument (i.e. return it in
+ * The modifier may reuse the mesh argument (i.e. return it in
* modified form), but must not release it.
*/
- struct DerivedMesh *(*applyModifier)(struct ModifierData *md, struct Object *ob,
- struct DerivedMesh *derivedData,
- ModifierApplyFlag flag);
-
- /* Like applyModifier but called during editmode (for supporting
- * modifiers).
- *
- * The derived object that is returned must support the operations that
- * are expected from editmode objects. The same qualifications regarding
- * derivedData apply as for applyModifier.
- */
- struct DerivedMesh *(*applyModifierEM)(struct ModifierData *md, struct Object *ob,
- struct BMEditMesh *editData,
- struct DerivedMesh *derivedData,
- ModifierApplyFlag flag);
+ struct Mesh *(*applyModifier)(struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *mesh);
/********************* Optional functions *********************/
@@ -270,21 +255,12 @@ typedef struct ModifierTypeInfo {
*
* This function is optional (assumes never disabled if not present).
*/
- bool (*isDisabled)(struct ModifierData *md, int userRenderParams);
-
- /* Add the appropriate relations to the DEP graph depending on the
- * modifier data.
- *
- * This function is optional.
- */
- void (*updateDepgraph)(struct ModifierData *md,
- const ModifierUpdateDepsgraphContext *ctx);
+ bool (*isDisabled)(const struct Scene *scene, struct ModifierData *md, bool userRenderParams);
/* Add the appropriate relations to the dependency graph.
*
* This function is optional.
*/
- /* TODO(sergey): Remove once we finally switched to the new depsgraph. */
void (*updateDepsgraph)(struct ModifierData *md,
const ModifierUpdateDepsgraphContext *ctx);
@@ -351,7 +327,7 @@ void modifier_free(struct ModifierData *md);
bool modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md);
-void modifier_copyData_generic(const struct ModifierData *md, struct ModifierData *target);
+void modifier_copyData_generic(const struct ModifierData *md, struct ModifierData *target, const int flag);
void modifier_copyData(struct ModifierData *md, struct ModifierData *target);
void modifier_copyData_ex(struct ModifierData *md, struct ModifierData *target, const int flag);
bool modifier_dependsOnTime(struct ModifierData *md);
@@ -361,7 +337,7 @@ bool modifier_couldBeCage(struct Scene *scene, struct ModifierData *md)
bool modifier_isCorrectableDeformed(struct ModifierData *md);
bool modifier_isSameTopology(ModifierData *md);
bool modifier_isNonGeometrical(ModifierData *md);
-bool modifier_isEnabled(struct Scene *scene, struct ModifierData *md, int required_mode);
+bool modifier_isEnabled(const struct Scene *scene, struct ModifierData *md, int required_mode);
void modifier_setError(struct ModifierData *md, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
bool modifier_isPreview(struct ModifierData *md);
@@ -387,6 +363,7 @@ bool modifiers_isClothEnabled(struct Object *ob);
bool modifiers_isParticleEnabled(struct Object *ob);
struct Object *modifiers_isDeformedByArmature(struct Object *ob);
+struct Object *modifiers_isDeformedByMeshDeform(struct Object *ob);
struct Object *modifiers_isDeformedByLattice(struct Object *ob);
struct Object *modifiers_isDeformedByCurve(struct Object *ob);
bool modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
@@ -433,28 +410,41 @@ void modifier_path_init(char *path, int path_maxlen, const char *name);
const char *modifier_path_relbase(struct Main *bmain, struct Object *ob);
const char *modifier_path_relbase_from_global(struct Object *ob);
-/* wrappers for modifier callbacks */
+/* wrappers for modifier callbacks that ensure valid normals */
-struct DerivedMesh *modwrap_applyModifier(
- ModifierData *md, struct Object *ob,
- struct DerivedMesh *dm,
- ModifierApplyFlag flag);
-
-struct DerivedMesh *modwrap_applyModifierEM(
- ModifierData *md, struct Object *ob,
- struct BMEditMesh *em,
- struct DerivedMesh *dm,
- ModifierApplyFlag flag);
+struct Mesh *modwrap_applyModifier(
+ ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *me);
void modwrap_deformVerts(
- ModifierData *md, struct Object *ob,
- struct DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts,
- ModifierApplyFlag flag);
+ ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct Mesh *me,
+ float (*vertexCos)[3], int numVerts);
void modwrap_deformVertsEM(
- ModifierData *md, struct Object *ob,
- struct BMEditMesh *em, struct DerivedMesh *dm,
+ ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct BMEditMesh *em, struct Mesh *me,
float (*vertexCos)[3], int numVerts);
+#define applyModifier_DM_wrapper(NEW_FUNC_NAME, OLD_FUNC_NAME) \
+ static Mesh *NEW_FUNC_NAME(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) \
+ { \
+ DerivedMesh *dm = CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_EVERYTHING); \
+ DerivedMesh *ndm = OLD_FUNC_NAME(md, ctx, dm); \
+ if (ndm != dm) dm->release(dm); \
+ DM_to_mesh(ndm, mesh, ctx->object, CD_MASK_EVERYTHING, true); \
+ return mesh; \
+ }
+
+/* wrappers for modifier callbacks that accept Mesh and select the proper implementation
+ * depending on if the modifier has been ported to Mesh or is still using DerivedMesh
+ */
+
+struct DerivedMesh *modifier_applyModifier_DM_deprecated(
+ struct ModifierData *md, const struct ModifierEvalContext *ctx,
+ struct DerivedMesh *dm);
+
+struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(
+ struct Object *ob_eval, bool *r_free_mesh);
+
#endif
diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h
index b79f37fd040..5071724d772 100644
--- a/source/blender/blenkernel/BKE_movieclip.h
+++ b/source/blender/blenkernel/BKE_movieclip.h
@@ -32,7 +32,7 @@
* \author Sergey Sharybin
*/
-struct EvaluationContext;
+struct Depsgraph;
struct ImBuf;
struct Main;
struct MovieClip;
@@ -84,10 +84,11 @@ struct ImBuf *BKE_movieclip_anim_ibuf_for_frame(struct MovieClip *clip, struct M
bool BKE_movieclip_has_cached_frame(struct MovieClip *clip, struct MovieClipUser *user);
bool BKE_movieclip_put_frame_if_possible(struct MovieClip *clip, struct MovieClipUser *user, struct ImBuf *ibuf);
-/* Evaluaiton. */
-void BKE_movieclip_eval_update(struct EvaluationContext *eval_ctx, struct MovieClip *clip);
+/* Evaluation. */
+void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, struct MovieClip *clip);
+void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, struct MovieClip *clip);
-/* cacheing flags */
+/* caching flags */
#define MOVIECLIP_CACHE_SKIP (1 << 0)
/* postprocessing flags */
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index d8199c96d6b..decfdc532a6 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -32,7 +32,11 @@
* \ingroup bke
*/
+#include "BLI_compiler_compat.h"
+
enum MultiresModifiedFlags;
+
+struct Depsgraph;
struct DerivedMesh;
struct MDisps;
struct Mesh;
@@ -41,6 +45,7 @@ struct Multires;
struct MultiresModifierData;
struct Object;
struct Scene;
+struct SubdivCCG;
struct MLoop;
struct MVert;
@@ -60,7 +65,7 @@ void multires_force_render_update(struct Object *ob);
void multires_force_external_reload(struct Object *ob);
/* internal, only called in subsurf_ccg.c */
-void multires_modifier_update_mdisps(struct DerivedMesh *dm);
+void multires_modifier_update_mdisps(struct DerivedMesh *dm, struct Scene *scene);
void multires_modifier_update_hidden(struct DerivedMesh *dm);
void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, struct Object *ob);
@@ -74,43 +79,35 @@ typedef enum {
struct DerivedMesh *multires_make_derived_from_derived(struct DerivedMesh *dm,
struct MultiresModifierData *mmd,
+ struct Scene *scene,
struct Object *ob,
MultiresFlags flags);
struct MultiresModifierData *find_multires_modifier_before(struct Scene *scene,
struct ModifierData *lastmd);
struct MultiresModifierData *get_multires_modifier(struct Scene *scene, struct Object *ob, bool use_first);
-struct DerivedMesh *get_multires_dm(struct Scene *scene, struct MultiresModifierData *mmd,
+int multires_get_level(const struct Scene *scene, const struct Object *ob, const struct MultiresModifierData *mmd,
+ bool render, bool ignore_simplify);
+struct DerivedMesh *get_multires_dm(struct Depsgraph *depsgraph, struct Scene *scene, struct MultiresModifierData *mmd,
struct Object *ob);
-void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction);
-void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Object *ob);
-void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int updateblock, int simple);
+struct Mesh *BKE_multires_create_mesh(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct MultiresModifierData *mmd, struct Object *ob);
+void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *object, int direction);
+void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *ob);
+void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Scene *scene, struct Object *ob, int updateblock, int simple);
void multiresModifier_sync_levels_ex(
- struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst);
-int multiresModifier_reshape(struct Scene *scene, struct MultiresModifierData *mmd,
- struct Object *dst, struct Object *src);
-int multiresModifier_reshapeFromDM(struct Scene *scene, struct MultiresModifierData *mmd,
- struct Object *ob, struct DerivedMesh *srcdm);
-int multiresModifier_reshapeFromDeformMod(struct Scene *scene, struct MultiresModifierData *mmd,
- struct Object *ob, struct ModifierData *md);
+ struct Scene *scene, struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst);
void multires_stitch_grids(struct Object *);
-/*switch mdisp data in dm between tangent and object space*/
-enum {
- MULTIRES_SPACE_TANGENT,
- MULTIRES_SPACE_OBJECT,
- MULTIRES_SPACE_ABSOLUTE
-};
-void multires_set_space(struct DerivedMesh *dm, struct Object *ob, int from, int to);
-
/* Related to the old multires */
void multires_free(struct Multires *mr);
void multires_load_old(struct Object *ob, struct Mesh *me);
void multires_load_old_250(struct Mesh *);
-void multiresModifier_scale_disp(struct Scene *scene, struct Object *ob);
-void multiresModifier_prepare_join(struct Scene *scene, struct Object *ob, struct Object *to_ob);
+void multiresModifier_scale_disp(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
+void multiresModifier_prepare_join(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct Object *to_ob);
int multires_mdisp_corners(struct MDisps *s);
@@ -121,4 +118,53 @@ void multires_topology_changed(struct Mesh *me);
void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v);
int mdisp_rot_face_to_crn(struct MVert *mvert, struct MPoly *mpoly, struct MLoop *mloops, const struct MLoopTri *lt, const int face_side, const float u, const float v, float *x, float *y);
+/* Reshaping, define in multires_reshape.c */
+
+bool multiresModifier_reshapeFromObject(
+ struct Depsgraph *depsgraph,
+ struct MultiresModifierData *mmd,
+ struct Object *dst,
+ struct Object *src);
+bool multiresModifier_reshapeFromDeformModifier(
+ struct Depsgraph *depsgraph,
+ struct MultiresModifierData *mmd,
+ struct Object *ob,
+ struct ModifierData *md);
+bool multiresModifier_reshapeFromCCG(
+ const int tot_level,
+ struct Mesh *coarse_mesh,
+ struct SubdivCCG *subdiv_ccg);
+
+/* Subdivision integration, defined in multires_subdiv.c */
+
+struct SubdivSettings;
+struct SubdivToMeshSettings;
+
+void BKE_multires_subdiv_settings_init(
+ struct SubdivSettings *settings,
+ const struct MultiresModifierData *mmd);
+
+/* TODO(sergey): Replace this set of boolean flags with bitmask. */
+void BKE_multires_subdiv_mesh_settings_init(
+ struct SubdivToMeshSettings *mesh_settings,
+ const struct Scene *scene,
+ const struct Object *object,
+ const struct MultiresModifierData *mmd,
+ const bool use_render_params,
+ const bool ignore_simplify);
+
+/* General helpers. */
+
+/* For a given partial derivatives of a ptex face get tangent matrix for
+ * displacement.
+ * Corner needs to be known to properly "rotate" partial derivatives.
+ */
+BLI_INLINE void BKE_multires_construct_tangent_matrix(
+ float tangent_matrix[3][3],
+ const float dPdu[3],
+ const float dPdv[3],
+ const int corner);
+
#endif /* __BKE_MULTIRES_H__ */
+
+#include "intern/multires_inline.h"
diff --git a/source/blender/blenkernel/BKE_navmesh_conversion.h b/source/blender/blenkernel/BKE_navmesh_conversion.h
deleted file mode 100644
index 3be363f4d7b..00000000000
--- a/source/blender/blenkernel/BKE_navmesh_conversion.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BKE_NAVMESH_CONVERSION_H__
-#define __BKE_NAVMESH_CONVERSION_H__
-
-/** \file BKE_navmesh_conversion.h
- * \ingroup bke
- */
-
-struct DerivedMesh;
-
-/* navmesh_conversion.c */
-int buildNavMeshDataByDerivedMesh(struct DerivedMesh *dm, int *vertsPerPoly,
- int *nverts, float **verts,
- int *ndtris, unsigned short **dtris,
- int *npolys, unsigned short **dmeshes,
- unsigned short **polys, int **dtrisToPolysMap,
- int **dtrisToTrisMap, int **trisToFacesMap);
-
-int buildRawVertIndicesData(struct DerivedMesh *dm, int *nverts, float **verts,
- int *ntris, unsigned short **tris, int **trisToFacesMap,
- int **recastData);
-
-int buildNavMeshData(const int nverts, const float *verts,
- const int ntris, const unsigned short *tris,
- const int *recastData, const int *trisToFacesMap,
- int *ndtris, unsigned short **dtris,
- int *npolys, unsigned short **dmeshes, unsigned short **polys,
- int *vertsPerPoly, int **dtrisToPolysMap, int **dtrisToTrisMap);
-
-int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys,
- unsigned short *polys, const unsigned short *dmeshes,
- const float *verts, const unsigned short *dtris,
- const int *dtrisToPolysMap);
-
-int polyNumVerts(const unsigned short *p, const int vertsPerPoly);
-int polyIsConvex(const unsigned short *p, const int vertsPerPoly, const float *verts);
-int polyFindVertex(const unsigned short *p, const int vertsPerPoly, unsigned short vertexIdx);
-float distPointToSegmentSq(const float *point, const float *a, const float *b);
-
-
-#endif /* NAVMESH_CONVERSION_H */
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index 37929bae042..a42819e52a2 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -47,13 +47,13 @@ struct PropertyRNA;
/* ----------------------------- */
/* Data Management */
-void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip);
-void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt);
-void BKE_nla_tracks_free(ListBase *tracks);
+void BKE_nlastrip_free(ListBase *strips, struct NlaStrip *strip, bool do_id_user);
+void BKE_nlatrack_free(ListBase *tracks, struct NlaTrack *nlt, bool do_id_user);
+void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user);
-struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain, struct NlaStrip *strip, const bool use_same_action);
-struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain, struct NlaTrack *nlt, const bool use_same_actions);
-void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, ListBase *src);
+struct NlaStrip *BKE_nlastrip_copy(struct Main *bmain, struct NlaStrip *strip, const bool use_same_action, const int flag);
+struct NlaTrack *BKE_nlatrack_copy(struct Main *bmain, struct NlaTrack *nlt, const bool use_same_actions, const int flag);
+void BKE_nla_tracks_copy(struct Main *bmain, ListBase *dst, ListBase *src, const int flag);
struct NlaTrack *BKE_nlatrack_add(struct AnimData *adt, struct NlaTrack *prev);
struct NlaStrip *BKE_nlastrip_new(struct bAction *act);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 09860972802..9b8febce756 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -74,6 +74,7 @@ struct PointerRNA;
struct RenderData;
struct Scene;
struct Tex;
+struct ViewRender;
struct SpaceNode;
struct ARegion;
struct ColorManagedViewSettings;
@@ -151,7 +152,7 @@ typedef struct bNodeType {
float width, minwidth, maxwidth;
float height, minheight, maxheight;
- short nclass, flag, compatibility;
+ short nclass, flag;
/* templates for static sockets */
bNodeSocketTemplate *inputs, *outputs;
@@ -250,10 +251,6 @@ typedef struct bNodeType {
#define NODE_CLASS_SHADER 40
#define NODE_CLASS_LAYOUT 100
-/* nodetype->compatibility */
-#define NODE_OLD_SHADING 1
-#define NODE_NEW_SHADING 2
-
/* node resize directions */
#define NODE_RESIZE_TOP 1
#define NODE_RESIZE_BOTTOM 2
@@ -343,7 +340,7 @@ void ntreeUserIncrefID(struct bNodeTree *ntree);
void ntreeUserDecrefID(struct bNodeTree *ntree);
-struct bNodeTree *ntreeFromID(struct ID *id);
+struct bNodeTree *ntreeFromID(const struct ID *id);
void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist, const bool lib_local);
struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type);
@@ -469,6 +466,10 @@ bool nodeAttachNodeCheck(struct bNode *node, struct bNode *parent);
void nodeAttachNode(struct bNode *node, struct bNode *parent);
void nodeDetachNode(struct bNode *node);
+void nodePositionRelative(struct bNode *from_node, struct bNode *to_node,
+ struct bNodeSocket *from_sock, struct bNodeSocket *to_sock);
+void nodePositionPropagate(struct bNode *node);
+
struct bNode *nodeFindNodebyName(struct bNodeTree *ntree, const char *name);
int nodeFindNode(struct bNodeTree *ntree, struct bNodeSocket *sock, struct bNode **nodep, int *sockindex);
struct bNode *nodeFindRootParent(bNode *node);
@@ -496,7 +497,6 @@ struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree);
void nodeUpdate(struct bNodeTree *ntree, struct bNode *node);
bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id);
void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
-void nodeSynchronizeID(struct bNode *node, bool copy_to_id);
int nodeSocketIsHidden(struct bNodeSocket *sock);
void ntreeTagUsedSockets(struct bNodeTree *ntree);
@@ -600,7 +600,6 @@ void node_type_update(struct bNodeType *ntype,
void node_type_exec(struct bNodeType *ntype, NodeInitExecFunction initexecfunc, NodeFreeExecFunction freeexecfunc, NodeExecFunction execfunc);
void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc);
void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *));
-void node_type_compatibility(struct bNodeType *ntype, short compatibility);
/** \} */
@@ -690,27 +689,33 @@ 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
* \{ */
-struct ShadeInput;
-struct ShadeResult;
/* note: types are needed to restore callbacks, don't change values */
/* range 1 - 100 is reserved for common nodes */
/* using toolbox, we add node groups by assuming the values below don't exceed NODE_GROUP_MENU for now */
-#define SH_NODE_OUTPUT 1
+//#define SH_NODE_OUTPUT 1
-#define SH_NODE_MATERIAL 100
+//#define SH_NODE_MATERIAL 100
#define SH_NODE_RGB 101
#define SH_NODE_VALUE 102
#define SH_NODE_MIX_RGB 103
#define SH_NODE_VALTORGB 104
#define SH_NODE_RGBTOBW 105
-#define SH_NODE_TEXTURE 106
+#define SH_NODE_SHADERTORGB 106
+//#define SH_NODE_TEXTURE 106
#define SH_NODE_NORMAL 107
-#define SH_NODE_GEOMETRY 108
+//#define SH_NODE_GEOMETRY 108
#define SH_NODE_MAPPING 109
#define SH_NODE_CURVE_VEC 110
#define SH_NODE_CURVE_RGB 111
@@ -718,7 +723,7 @@ struct ShadeResult;
#define SH_NODE_MATH 115
#define SH_NODE_VECT_MATH 116
#define SH_NODE_SQUEEZE 117
-#define SH_NODE_MATERIAL_EXT 118
+//#define SH_NODE_MATERIAL_EXT 118
#define SH_NODE_INVERT 119
#define SH_NODE_SEPRGB 120
#define SH_NODE_COMBRGB 121
@@ -727,7 +732,7 @@ struct ShadeResult;
#define SH_NODE_OUTPUT_MATERIAL 124
#define SH_NODE_OUTPUT_WORLD 125
-#define SH_NODE_OUTPUT_LAMP 126
+#define SH_NODE_OUTPUT_LIGHT 126
#define SH_NODE_FRESNEL 127
#define SH_NODE_MIX_SHADER 128
#define SH_NODE_ATTRIBUTE 129
@@ -790,6 +795,7 @@ struct ShadeResult;
#define SH_NODE_TEX_POINTDENSITY 192
#define SH_NODE_BSDF_PRINCIPLED 193
#define SH_NODE_TEX_IES 194
+#define SH_NODE_EEVEE_SPECULAR 195
#define SH_NODE_BEVEL 197
#define SH_NODE_DISPLACEMENT 198
#define SH_NODE_VECTOR_DISPLACEMENT 199
@@ -806,14 +812,11 @@ struct ShadeResult;
struct bNodeTreeExec *ntreeShaderBeginExecTree(struct bNodeTree *ntree);
void ntreeShaderEndExecTree(struct bNodeTreeExec *exec);
-bool ntreeShaderExecTree(struct bNodeTree *ntree, struct ShadeInput *shi, struct ShadeResult *shr);
-void ntreeShaderGetTexcoMode(struct bNodeTree *ntree, int osa, short *texco, int *mode);
-
-/* switch material render loop */
-extern void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *);
-void set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, struct ShadeResult *));
+bool ntreeShaderExecTree(struct bNodeTree *ntree, int thread);
+struct bNode *ntreeShaderOutputNode(struct bNodeTree *ntree, int target);
-void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMaterial *mat, short compatibility);
+void ntreeGPUMaterialNodes(struct bNodeTree *localtree, struct GPUMaterial *mat,
+ bool *has_surface_output, bool *has_volume_output);
/** \} */
@@ -985,7 +988,7 @@ void ntreeCompositTagRender(struct Scene *sce);
int ntreeCompositTagAnimated(struct bNodeTree *ntree);
void ntreeCompositTagGenerators(struct bNodeTree *ntree);
void ntreeCompositUpdateRLayers(struct bNodeTree *ntree);
-void ntreeCompositRegisterPass(struct bNodeTree *ntree, struct Scene *scene, struct SceneRenderLayer *srl, const char *name, int type);
+void ntreeCompositRegisterPass(struct bNodeTree *ntree, struct Scene *scene, struct ViewLayer *view_layer, const char *name, int type);
void ntreeCompositClearTags(struct bNodeTree *ntree);
struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree, struct bNode *node,
@@ -1049,10 +1052,19 @@ struct bNodeTreeExec *ntreeTexBeginExecTree(struct bNodeTree *ntree);
void ntreeTexEndExecTree(struct bNodeTreeExec *exec);
int ntreeTexExecTree(struct bNodeTree *ntree, struct TexResult *target,
float coord[3], float dxt[3], float dyt[3], int osatex, const short thread,
- struct Tex *tex, short which_output, int cfra, int preview, struct ShadeInput *shi, struct MTex *mtex);
+ struct Tex *tex, short which_output, int cfra, int preview, struct MTex *mtex);
/** \} */
void init_nodesystem(void);
void free_nodesystem(void);
+/* -------------------------------------------------------------------- */
+/* evaluation support, */
+
+struct Depsgraph;
+
+void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
+ struct bNodeTree *ntree_dst,
+ const struct bNodeTree *ntree_src);
+
#endif /* __BKE_NODE_H__ */
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 677d6b3fba2..8085c541600 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -36,52 +36,73 @@ extern "C" {
#include "BLI_compiler_attrs.h"
struct Base;
-struct EvaluationContext;
+struct Depsgraph;
+struct GpencilModifierData;
struct Scene;
+struct ShaderFxData;
+struct ViewLayer;
+struct ID;
struct Object;
struct BoundBox;
struct View3D;
struct SoftBody;
-struct BulletSoftBody;
struct MovieClip;
struct Main;
+struct Mesh;
struct RigidBodyWorld;
struct HookModifierData;
struct ModifierData;
+struct HookGpencilModifierData;
+
+#include "DNA_object_enums.h"
void BKE_object_workob_clear(struct Object *workob);
-void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struct Object *workob);
+void BKE_object_workob_calc_parent(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct Object *workob);
void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
-struct SoftBody *copy_softbody(const struct SoftBody *sb, const int flag);
-struct BulletSoftBody *copy_bulletsoftbody(const struct BulletSoftBody *sb, const int flag);
+void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag);
struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys, const int flag);
void BKE_object_copy_particlesystems(struct Object *ob_dst, const struct Object *ob_src, const int flag);
-void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_particlesystems(struct Object *ob);
void BKE_object_free_softbody(struct Object *ob);
-void BKE_object_free_bulletsoftbody(struct Object *ob);
void BKE_object_free_curve_cache(struct Object *ob);
-void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob);
void BKE_object_free(struct Object *ob);
void BKE_object_free_derived_caches(struct Object *ob);
+void BKE_object_free_derived_mesh_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
+void BKE_object_modifier_gpencil_hook_reset(struct Object *ob, struct HookGpencilModifierData *hmd);
+bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModifierData *md);
+
+bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
-void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src);
+void BKE_object_link_modifiers(struct Scene *scene, struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_modifiers(struct Object *ob, const int flag);
+void BKE_object_free_shaderfx(struct Object *ob, const int flag);
-void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob);
+void BKE_object_make_proxy(struct Main *bmain, struct Object *ob, struct Object *target, struct Object *gob);
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
bool BKE_object_exists_check(struct Main *bmain, const struct Object *obtest);
bool BKE_object_is_in_editmode(const struct Object *ob);
bool BKE_object_is_in_editmode_vgroup(const struct Object *ob);
bool BKE_object_is_in_wpaint_select_vert(const struct Object *ob);
+bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode);
+bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode);
+
+bool BKE_object_data_is_in_editmode(const struct ID *id);
+
+typedef enum eObjectVisibilityCheck {
+ OB_VISIBILITY_CHECK_FOR_VIEWPORT,
+ OB_VISIBILITY_CHECK_FOR_RENDER,
+ OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE,
+} eObjectVisibilityCheck;
+
+bool BKE_object_is_visible(const struct Object *ob, const eObjectVisibilityCheck mode);
void BKE_object_init(struct Object *ob);
struct Object *BKE_object_add_only_object(
@@ -89,22 +110,21 @@ struct Object *BKE_object_add_only_object(
int type, const char *name)
ATTR_NONNULL(1) ATTR_RETURNS_NONNULL;
struct Object *BKE_object_add(
- struct Main *bmain, struct Scene *scene,
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer,
int type, const char *name)
- ATTR_NONNULL(1, 2) ATTR_RETURNS_NONNULL;
+ ATTR_NONNULL(1, 2, 3) ATTR_RETURNS_NONNULL;
+struct Object *BKE_object_add_from(
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer,
+ int type, const char *name, struct Object *ob_src)
+ ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL;
+struct Object *BKE_object_add_for_data(
+ struct Main *bmain, struct ViewLayer *view_layer,
+ int type, const char *name, struct ID *data, bool do_id_user) ATTR_RETURNS_NONNULL;
void *BKE_object_obdata_add_from_type(
struct Main *bmain,
int type, const char *name)
ATTR_NONNULL(1);
-void BKE_object_lod_add(struct Object *ob);
-void BKE_object_lod_sort(struct Object *ob);
-bool BKE_object_lod_remove(struct Object *ob, int level);
-void BKE_object_lod_update(struct Object *ob, const float camera_position[3]);
-bool BKE_object_lod_is_usable(struct Object *ob, struct Scene *scene);
-struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene);
-struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene);
-
void BKE_object_copy_data(struct Main *bmain, struct Object *ob_dst, const struct Object *ob_src, const int flag);
struct Object *BKE_object_copy(struct Main *bmain, const struct Object *ob);
void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool lib_local);
@@ -120,20 +140,36 @@ void BKE_object_mat3_to_rot(struct Object *ob, float mat[3][3], bool use_compat)
void BKE_object_to_mat3(struct Object *ob, float mat[3][3]);
void BKE_object_to_mat4(struct Object *ob, float mat[4][4]);
void BKE_object_apply_mat4(struct Object *ob, float mat[4][4], const bool use_compat, const bool use_parent);
+void BKE_object_apply_mat4_ex(struct Object *ob, float mat[4][4], struct Object *parent, float parentinv[4][4], const bool use_compat);
void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4]);
bool BKE_object_pose_context_check(const struct Object *ob);
struct Object *BKE_object_pose_armature_get(struct Object *ob);
+struct Object *BKE_object_pose_armature_get_visible(struct Object *ob, struct ViewLayer *view_layer);
-void BKE_object_get_parent_matrix(struct Scene *scene, struct Object *ob, struct Object *par, float parentmat[4][4]);
-void BKE_object_where_is_calc(struct Scene *scene, struct Object *ob);
+struct Object **BKE_object_pose_array_get_ex(struct ViewLayer *view_layer, unsigned int *r_objects_len, bool unique);
+struct Object **BKE_object_pose_array_get_unique(struct ViewLayer *view_layer, unsigned int *r_objects_len);
+struct Object **BKE_object_pose_array_get(struct ViewLayer *view_layer, unsigned int *r_objects_len);
+
+struct Base **BKE_object_pose_base_array_get_ex(struct ViewLayer *view_layer, unsigned int *r_bases_len, bool unique);
+struct Base **BKE_object_pose_base_array_get_unique(struct ViewLayer *view_layer, unsigned int *r_bases_len);
+struct Base **BKE_object_pose_base_array_get(struct ViewLayer *view_layer, unsigned int *r_bases_len);
+
+void BKE_object_get_parent_matrix(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ struct Object *par, float parentmat[4][4]);
+void BKE_object_where_is_calc(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void BKE_object_where_is_calc_ex(
- struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3]);
-void BKE_object_where_is_calc_time(struct Scene *scene, struct Object *ob, float ctime);
+ struct Depsgraph *depsgraph, struct Scene *scene, struct RigidBodyWorld *rbw,
+ struct Object *ob, float r_originmat[3][3]);
+void BKE_object_where_is_calc_time(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime);
void BKE_object_where_is_calc_time_ex(
- struct Scene *scene, struct Object *ob, float ctime,
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float ctime,
struct RigidBodyWorld *rbw, float r_originmat[3][3]);
-void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float obmat[4][4]);
+void BKE_object_where_is_calc_mat4(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float obmat[4][4]);
/* possibly belong in own moduke? */
struct BoundBox *BKE_boundbox_alloc_unit(void);
@@ -147,20 +183,18 @@ void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
void BKE_object_dimensions_set(struct Object *ob, const float value[3]);
void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
+void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval);
void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
bool BKE_object_minmax_dupli(
- struct Main *bmain, struct Scene *scene,
- struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ float r_min[3], float r_max[3], const bool use_hidden);
/* sometimes min-max isn't enough, we need to loop over each point */
void BKE_object_foreach_display_point(
struct Object *ob, float obmat[4][4],
void (*func_cb)(const float[3], void *), void *user_data);
void BKE_scene_foreach_display_point(
- struct Main *bmain,
- struct Scene *scene,
- struct View3D *v3d,
- const short flag,
+ struct Depsgraph *depsgraph,
void (*func_cb)(const float[3], void *), void *user_data);
bool BKE_object_parent_loop_check(const struct Object *parent, const struct Object *ob);
@@ -188,54 +222,59 @@ void BKE_object_tfm_protected_restore(
/* Dependency graph evaluation callbacks. */
void BKE_object_eval_local_transform(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Object *ob);
void BKE_object_eval_parent(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void BKE_object_eval_constraints(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
-void BKE_object_eval_done(struct EvaluationContext *eval_ctx, struct Object *ob);
+void BKE_object_eval_done(struct Depsgraph *depsgraph, struct Object *ob);
bool BKE_object_eval_proxy_copy(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Object *object);
void BKE_object_eval_uber_transform(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Object *ob);
void BKE_object_eval_uber_data(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void BKE_object_eval_cloth(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *object);
-
void BKE_object_eval_transform_all(
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *object);
-void BKE_object_handle_data_update(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx,
- struct Scene *scene,
- struct Object *ob);
-void BKE_object_handle_update(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx,
+void BKE_object_eval_update_shading(
+ struct Depsgraph *depsgraph,
+ struct Object *object);
+void BKE_object_data_select_update(
+ struct Depsgraph *depsgraph,
+ struct ID *object_data);
+
+void BKE_object_eval_flush_base_flags(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene, const int view_layer_index,
+ struct Object *object, int base_index,
+ const bool is_from_set);
+
+void BKE_object_handle_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
+void BKE_object_handle_update(struct Depsgraph *depsgraph,
+ struct Scene *scene, struct Object *ob);
void BKE_object_handle_update_ex(
- struct Main *bmain,
- struct EvaluationContext *eval_ctx,
+ struct Depsgraph *depsgraph,
struct Scene *scene, struct Object *ob,
struct RigidBodyWorld *rbw,
const bool do_proxy_update);
@@ -243,6 +282,11 @@ void BKE_object_sculpt_modifiers_changed(struct Object *ob);
int BKE_object_obdata_texspace_get(struct Object *ob, short **r_texflag, float **r_loc, float **r_size, float **r_rot);
+struct Mesh *BKE_object_get_evaluated_mesh(const struct Depsgraph *depsgraph, struct Object *ob);
+struct Mesh *BKE_object_get_final_mesh(struct Object *object);
+struct Mesh *BKE_object_get_pre_modified_mesh(struct Object *object);
+struct Mesh *BKE_object_get_original_mesh(struct Object *object);
+
int BKE_object_insert_ptcache(struct Object *ob);
void BKE_object_delete_ptcache(struct Object *ob, int index);
struct KeyBlock *BKE_object_shapekey_insert(struct Main *bmain, struct Object *ob, const char *name, const bool from_mix);
@@ -263,6 +307,10 @@ void BKE_object_data_relink(struct Object *ob);
struct MovieClip *BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, bool use_default);
+void BKE_object_runtime_reset(struct Object *object);
+
+void BKE_object_batch_cache_dirty_tag(struct Object *ob);
+
/* this function returns a superset of the scenes selection based on relationships */
typedef enum eObRelationTypes {
@@ -282,20 +330,17 @@ typedef enum eObjectSet {
} eObjectSet;
struct LinkNode *BKE_object_relational_superset(
- struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter);
+ struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter);
struct LinkNode *BKE_object_groups(struct Main *bmain, struct Object *ob);
-void BKE_object_groups_clear(
- struct Main *bmain, struct Scene *scene, struct Base *base, struct Object *object);
+void BKE_object_groups_clear(struct Main *bmain, struct Object *object);
struct KDTree *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
bool BKE_object_modifier_use_time(struct Object *ob, struct ModifierData *md);
bool BKE_object_modifier_update_subframe(
- struct Main *bmain, struct EvaluationContext *eval_ctx,
- struct Scene *scene, struct Object *ob, bool update_mesh,
- int parent_recursion, float frame,
- int type);
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ bool update_mesh, int parent_recursion, float frame, int type);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_object_facemap.h b/source/blender/blenkernel/BKE_object_facemap.h
new file mode 100644
index 00000000000..2607e5aa2dd
--- /dev/null
+++ b/source/blender/blenkernel/BKE_object_facemap.h
@@ -0,0 +1,53 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Antony Riakiotakis
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_OBJECT_FACEMAP_H__
+#define __BKE_OBJECT_FACEMAP_H__
+
+/** \file BKE_object_facemap.h
+ * \ingroup bke
+ * \brief Functions for dealing with object face-maps.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bFaceMap;
+struct ListBase;
+struct Object;
+
+struct bFaceMap *BKE_object_facemap_add(struct Object *ob);
+struct bFaceMap *BKE_object_facemap_add_name(struct Object *ob, const char *name);
+void BKE_object_facemap_remove(struct Object *ob, struct bFaceMap *fmap);
+void BKE_object_facemap_clear(struct Object *ob);
+
+int BKE_object_facemap_name_index(struct Object *ob, const char *name);
+void BKE_object_facemap_unique_name(struct Object *ob, struct bFaceMap *fmap);
+struct bFaceMap *BKE_object_facemap_find_name(struct Object *ob, const char *name);
+void BKE_object_facemap_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BKE_OBJECT_FACEMAP_H__ */
diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h
index 3ea104e656a..e18a063ff52 100644
--- a/source/blender/blenkernel/BKE_ocean.h
+++ b/source/blender/blenkernel/BKE_ocean.h
@@ -31,6 +31,8 @@
extern "C" {
#endif
+struct OceanModifierData;
+
typedef struct OceanResult {
float disp[3];
float normal[3];
@@ -72,6 +74,8 @@ typedef struct OceanCache {
struct Ocean *BKE_ocean_add(void);
void BKE_ocean_free_data(struct Ocean *oc);
void BKE_ocean_free(struct Ocean *oc);
+bool BKE_ocean_ensure(struct OceanModifierData *omd);
+void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData const *omd);
void BKE_ocean_init(
struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
@@ -99,6 +103,8 @@ void BKE_ocean_cache_eval_uv(struct OceanCache *och, struct OceanResult *ocr, in
void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, int f, int i, int j);
void BKE_ocean_free_cache(struct OceanCache *och);
+void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_outliner_treehash.h b/source/blender/blenkernel/BKE_outliner_treehash.h
index 454edb40c4e..8a14f8fb041 100644
--- a/source/blender/blenkernel/BKE_outliner_treehash.h
+++ b/source/blender/blenkernel/BKE_outliner_treehash.h
@@ -36,8 +36,12 @@ void *BKE_outliner_treehash_create_from_treestore(struct BLI_mempool *treestore)
/* full rebuild for already allocated hashtable */
void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore);
-/* full rebuild for already allocated hashtable */
+/* clear element usage flags */
+void BKE_outliner_treehash_clear_used(void *treehash);
+
+/* Add/remove hashtable elements */
void BKE_outliner_treehash_add_element(void *treehash, struct TreeStoreElem *elem);
+void BKE_outliner_treehash_remove_element(void *treehash, struct TreeStoreElem *elem);
/* find first unused element with specific type, nr and id */
struct TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, short nr, struct ID *id);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index a132af41567..6f54e2b3b17 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -33,13 +33,16 @@
*/
struct bContext;
+struct bToolRef;
struct BMesh;
struct BMFace;
struct Brush;
struct CurveMapping;
+struct EnumPropertyItem;
struct MeshElemMap;
struct GridPaintMask;
struct Main;
+struct Mesh;
struct MLoop;
struct MLoopTri;
struct MFace;
@@ -52,11 +55,15 @@ struct PaletteColor;
struct PBVH;
struct ReportList;
struct Scene;
+struct ViewLayer;
struct Sculpt;
struct StrokeCache;
+struct SubdivCCG;
struct Tex;
struct ImagePool;
struct UnifiedPaintSettings;
+struct Depsgraph;
+struct ToolSettings;
enum eOverlayFlags;
@@ -77,7 +84,9 @@ typedef enum ePaintMode {
/** Image space (2D painting). */
ePaintTexture2D = 4,
ePaintSculptUV = 5,
- ePaintInvalid = 6
+ ePaintGpencil = 6,
+
+ ePaintInvalid = 7,
} ePaintMode;
/* overlay invalidation */
@@ -94,14 +103,15 @@ typedef enum eOverlayControlFlags {
PAINT_OVERLAY_OVERRIDE_PRIMARY | \
PAINT_OVERLAY_OVERRIDE_CURSOR)
-void BKE_paint_invalidate_overlay_tex(struct Scene *scene, const struct Tex *tex);
-void BKE_paint_invalidate_cursor_overlay(struct Scene *scene, struct CurveMapping *curve);
+void BKE_paint_invalidate_overlay_tex(struct Scene *scene, struct ViewLayer *view_layer, const struct Tex *tex);
+void BKE_paint_invalidate_cursor_overlay(struct Scene *scene, struct ViewLayer *view_layer, struct CurveMapping *curve);
void BKE_paint_invalidate_overlay_all(void);
eOverlayControlFlags BKE_paint_get_overlay_flags(void);
void BKE_paint_reset_overlay_invalid(eOverlayControlFlags flag);
void BKE_paint_set_overlay_override(enum eOverlayFlags flag);
/* palettes */
+void BKE_palette_init(struct Palette *palette);
void BKE_palette_free(struct Palette *palette);
struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
void BKE_palette_copy_data(
@@ -121,17 +131,24 @@ void BKE_paint_curve_copy_data(
struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, const struct PaintCurve *pc);
void BKE_paint_curve_make_local(struct Main *bmain, struct PaintCurve *pc, const bool lib_local);
+bool BKE_paint_ensure(const struct ToolSettings *ts, struct Paint **r_paint);
void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3]);
void BKE_paint_free(struct Paint *p);
void BKE_paint_copy(struct Paint *src, struct Paint *tar, const int flag);
+void BKE_paint_runtime_init(const struct ToolSettings *ts, struct Paint *paint);
+
void BKE_paint_cavity_curve_preset(struct Paint *p, int preset);
-eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode);
+eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode);
struct Paint *BKE_paint_get_active_from_paintmode(struct Scene *sce, ePaintMode mode);
-struct Paint *BKE_paint_get_active(struct Scene *sce);
+const struct EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode);
+const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode);
+uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode);
+struct Paint *BKE_paint_get_active(struct Scene *sce, struct ViewLayer *view_layer);
struct Paint *BKE_paint_get_active_from_context(const struct bContext *C);
ePaintMode BKE_paintmode_get_active_from_context(const struct bContext *C);
+ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref);
struct Brush *BKE_paint_brush(struct Paint *paint);
void BKE_paint_brush_set(struct Paint *paint, struct Brush *br);
struct Palette *BKE_paint_palette(struct Paint *paint);
@@ -165,6 +182,15 @@ void paint_update_brush_rake_rotation(struct UnifiedPaintSettings *ups, struct B
void BKE_paint_stroke_get_average(struct Scene *scene, struct Object *ob, float stroke[3]);
+
+/* Tool slot API. */
+void BKE_paint_toolslots_init_from_main(struct Main *bmain);
+void BKE_paint_toolslots_len_ensure(struct Paint *paint, int len);
+void BKE_paint_toolslots_brush_update_ex(struct Paint *paint, struct Brush *brush);
+void BKE_paint_toolslots_brush_update(struct Paint *paint);
+void BKE_paint_toolslots_brush_validate(struct Main *bmain, struct Paint *paint);
+struct Brush *BKE_paint_toolslots_brush_get(struct Paint *paint, int slot_index);
+
/* Used for both vertex color and weight paint */
struct SculptVertexPaintGeomMap {
int *vert_map_mem;
@@ -186,7 +212,8 @@ typedef struct SculptSession {
float *vmask;
/* Mesh connectivity */
- const struct MeshElemMap *pmap;
+ struct MeshElemMap *pmap;
+ int *pmap_mem;
/* BMesh for dynamic topology sculpting */
struct BMesh *bm;
@@ -196,6 +223,9 @@ typedef struct SculptSession {
/* Undo/redo log for dynamic topology sculpting */
struct BMLog *bm_log;
+ /* Limit surface/grids. */
+ struct SubdivCCG *subdiv_ccg;
+
/* PBVH acceleration structure */
struct PBVH *pbvh;
bool show_diffuse_color;
@@ -251,13 +281,16 @@ void BKE_sculptsession_free_deformMats(struct SculptSession *ss);
void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
-void BKE_sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob,
- bool need_pmap, bool need_mask);
+void BKE_sculpt_update_mesh_elements(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Sculpt *sd, struct Object *ob,
+ bool need_pmap, bool need_mask);
struct MultiresModifierData *BKE_sculpt_multires_active(struct Scene *scene, struct Object *ob);
int BKE_sculpt_mask_layers_ensure(struct Object *ob,
struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
+struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct Object *ob);
+
enum {
SCULPT_MASK_LAYER_CALC_VERT = (1 << 0),
SCULPT_MASK_LAYER_CALC_LOOP = (1 << 1)
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 54c927aaa99..aa00024b27b 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -49,7 +49,7 @@ struct ParticleSettings;
struct Main;
struct Object;
struct Scene;
-struct DerivedMesh;
+struct Depsgraph;
struct ModifierData;
struct MTFace;
struct MCol;
@@ -62,6 +62,8 @@ struct RNG;
struct BVHTreeRay;
struct BVHTreeRayHit;
struct EdgeHash;
+struct Depsgraph;
+struct ViewLayer;
#define PARTICLE_COLLISION_MAX_COLLISIONS 10
@@ -77,6 +79,7 @@ struct EdgeHash;
/* common stuff that many particle functions need */
typedef struct ParticleSimulationData {
+ struct Depsgraph *depsgraph;
struct Scene *scene;
struct Object *ob;
struct ParticleSystem *psys;
@@ -86,6 +89,8 @@ typedef struct ParticleSimulationData {
* maximum value per time step is important. Only sph_integrate makes use of
* this at the moment. Other solvers could, too. */
float courant_num;
+ /* Only valid during dynamics_step(). */
+ struct RNG *rng;
} ParticleSimulationData;
typedef struct SPHData {
@@ -133,7 +138,7 @@ typedef struct ParticleCacheKey {
typedef struct ParticleThreadContext {
/* shared */
struct ParticleSimulationData sim;
- struct DerivedMesh *dm;
+ struct Mesh *mesh;
struct Material *ma;
/* distribution */
@@ -144,7 +149,7 @@ typedef struct ParticleThreadContext {
float *jit, *jitoff, *weight;
float maxweight;
- int *index, *skip, jitlevel;
+ int *index, jitlevel;
int cfrom, distr;
@@ -286,8 +291,8 @@ BLI_INLINE void psys_frand_vec(ParticleSystem *psys, unsigned int seed, float ve
int count_particles(struct ParticleSystem *psys);
int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur);
-int psys_get_child_number(struct Scene *scene, struct ParticleSystem *psys);
-int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys);
+int psys_get_child_number(struct Scene *scene, struct ParticleSystem *psys, const bool use_render_params);
+int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys, const bool use_render_params);
struct ParticleSystem *psys_get_current(struct Object *ob);
/* for rna */
@@ -298,10 +303,12 @@ void psys_set_current_num(Object *ob, int index);
struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim);
-bool psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys);
+struct ParticleSystem *psys_orig_get(struct ParticleSystem *psys);
+bool psys_in_edit_mode(struct Depsgraph *depsgraph, const struct ParticleSystem *psys);
bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
bool psys_check_edited(struct ParticleSystem *psys);
+void psys_find_group_weights(struct ParticleSettings *part);
void psys_check_group_weights(struct ParticleSettings *part);
int psys_uses_gravity(struct ParticleSimulationData *sim);
void BKE_particlesettings_fluid_default_settings(struct ParticleSettings *part);
@@ -311,8 +318,9 @@ void BKE_particlesettings_free(struct ParticleSettings *part);
void psys_free_path_cache(struct ParticleSystem *psys, struct PTCacheEdit *edit);
void psys_free(struct Object *ob, struct ParticleSystem *psys);
-void psys_render_set(struct Object *ob, struct ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset);
-void psys_render_restore(struct Object *ob, struct ParticleSystem *psys);
+/* Copy. */
+void psys_copy_particles(struct ParticleSystem *psys_dst, struct ParticleSystem *psys_src);
+
bool psys_render_simplify_params(struct ParticleSystem *psys, struct ChildParticle *cpa, float *params);
void psys_interpolate_uvs(const struct MTFace *tface, int quad, const float w[4], float uvco[2]);
@@ -323,7 +331,7 @@ void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int tim
CustomDataMask psys_emitter_customdata_mask(struct ParticleSystem *psys);
void psys_particle_on_emitter(struct ParticleSystemModifierData *psmd, int distr, int index, int index_dmcache,
float fuv[4], float foffset, float vec[3], float nor[3],
- float utan[3], float vtan[3], float orco[3], float ornor[3]);
+ float utan[3], float vtan[3], float orco[3]);
struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct ParticleSystem *psys);
struct ModifierData *object_add_particle_system(
@@ -341,9 +349,9 @@ void psys_reset(struct ParticleSystem *psys, int mode);
void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render_params);
void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, const bool use_render_params);
-void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params);
+void psys_cache_edit_paths(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params);
void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, const bool editupdate, const bool use_render_params);
-int do_guides(struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
+int do_guides(struct Depsgraph *depsgraph, struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors);
float psys_get_timestep(struct ParticleSimulationData *sim);
float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime);
@@ -356,7 +364,7 @@ void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
void BKE_particlesettings_twist_curve_init(struct ParticleSettings *part);
void psys_apply_child_modifiers(struct ParticleThreadContext *ctx, struct ListBase *modifiers,
- struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
+ struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], float hairmat[4][4],
struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys, const float parent_orco[3]);
void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
@@ -376,7 +384,7 @@ void psys_tasks_create(struct ParticleThreadContext *ctx, int startpart, int end
void psys_tasks_free(struct ParticleTask *tasks, int numtasks);
void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
-void psys_apply_hair_lattice(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
+void psys_apply_hair_lattice(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
/* particle_system.c */
struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt);
@@ -391,7 +399,7 @@ void psys_check_boid_data(struct ParticleSystem *psys);
void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra);
-void particle_system_update(struct Main *bmain, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
+void particle_system_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
/* Callback format for performing operations on ID-pointers for particle systems */
typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cb_flag);
@@ -409,65 +417,38 @@ void psys_free_particles(struct ParticleSystem *psys);
void psys_free_children(struct ParticleSystem *psys);
void psys_interpolate_particle(short type, struct ParticleKey keys[4], float dt, struct ParticleKey *result, bool velocity);
-void psys_vec_rot_to_face(struct DerivedMesh *dm, struct ParticleData *pa, float vec[3]);
-void psys_mat_hair_to_object(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
-void psys_mat_hair_to_global(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
-void psys_mat_hair_to_orco(struct Object *ob, struct DerivedMesh *dm, short from, struct ParticleData *pa, float hairmat[4][4]);
+void psys_vec_rot_to_face(struct Mesh *mesh, struct ParticleData *pa, float vec[3]);
+void psys_mat_hair_to_object(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4]);
+void psys_mat_hair_to_global(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4]);
+void psys_mat_hair_to_orco(struct Object *ob, struct Mesh *mesh, short from, struct ParticleData *pa, float hairmat[4][4]);
float psys_get_dietime_from_cache(struct PointCache *cache, int index);
void psys_free_pdd(struct ParticleSystem *psys);
-float *psys_cache_vgroup(struct DerivedMesh *dm, struct ParticleSystem *psys, int vgroup);
+float *psys_cache_vgroup(struct Mesh *mesh, struct ParticleSystem *psys, int vgroup);
void psys_get_texture(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleTexture *ptex, int event, float cfra);
void psys_interpolate_face(struct MVert *mvert, struct MFace *mface, struct MTFace *tface,
float (*orcodata)[3], float w[4], float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3]);
-float psys_particle_value_from_verts(struct DerivedMesh *dm, short from, struct ParticleData *pa, float *values);
+ float orco[3]);
+float psys_particle_value_from_verts(struct Mesh *mesh, short from, struct ParticleData *pa, float *values);
void psys_get_from_key(struct ParticleKey *key, float loc[3], float vel[3], float rot[4], float *time);
/* BLI_bvhtree_ray_cast callback */
void BKE_psys_collision_neartest_cb(void *userdata, int index, const struct BVHTreeRay *ray, struct BVHTreeRayHit *hit);
-void psys_particle_on_dm(struct DerivedMesh *dm_final, int from, int index, int index_dmcache,
+void psys_particle_on_dm(struct Mesh *mesh_final, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3]);
+ float orco[3]);
/* particle_system.c */
void distribute_particles(struct ParticleSimulationData *sim, int from);
void initialize_particle(struct ParticleSimulationData *sim, struct ParticleData *pa);
-void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, struct ParticleSystem *psys);
-int psys_particle_dm_face_lookup(struct DerivedMesh *dm_final, struct DerivedMesh *dm_deformed, int findex, const float fw[4], struct LinkNode **poly_nodes);
+void psys_calc_dmcache(struct Object *ob, struct Mesh *mesh_final, struct Mesh *mesh_original, struct ParticleSystem *psys);
+int psys_particle_dm_face_lookup(struct Mesh *mesh_final, struct Mesh *mesh_original, int findex, const float fw[4], struct LinkNode **poly_nodes);
void reset_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, float dtime, float cfra);
-float psys_get_current_display_percentage(struct ParticleSystem *psys);
-
-typedef struct ParticleRenderElem {
- int curchild, totchild, reduce;
- float lambda, t, scalemin, scalemax;
-} ParticleRenderElem;
-
-typedef struct ParticleRenderData {
- ChildParticle *child;
- ParticleCacheKey **pathcache;
- ParticleCacheKey **childcache;
- ListBase pathcachebufs, childcachebufs;
- int totchild, totcached, totchildcache;
- struct DerivedMesh *dm;
- int totdmvert, totdmedge, totdmface;
-
- float mat[4][4];
- float viewmat[4][4], winmat[4][4];
- int winx, winy;
-
- int do_simplify;
- int timeoffset;
- ParticleRenderElem *elems;
-
- /* ORIGINDEX */
- const int *index_mf_to_mpoly;
- const int *index_mp_to_orig;
-} ParticleRenderData;
+float psys_get_current_display_percentage(struct ParticleSystem *psys, const bool use_render_params);
/* psys_reset */
#define PSYS_RESET_ALL 1
@@ -481,10 +462,17 @@ typedef struct ParticleRenderData {
/* **** Depsgraph evaluation **** */
-struct EvaluationContext;
+struct Depsgraph;
-void BKE_particle_system_eval_init(struct EvaluationContext *eval_ctx,
+void BKE_particle_system_eval_init(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
#endif
+
+/* Draw Cache */
+enum {
+ BKE_PARTICLE_BATCH_DIRTY_ALL = 0,
+};
+void BKE_particle_batch_cache_dirty_tag(struct ParticleSystem *psys, int mode);
+void BKE_particle_batch_cache_free(struct ParticleSystem *psys);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 1fede116193..47fedb565fc 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -30,6 +30,7 @@
#include "BLI_ghash.h"
#include "BLI_utildefines.h"
+struct GPUBatch;
struct CCGElem;
struct CCGKey;
struct CCGDerivedMesh;
@@ -127,10 +128,9 @@ bool BKE_pbvh_node_find_nearest_to_ray(
/* Drawing */
-void BKE_pbvh_node_draw(PBVHNode *node, void *data);
-void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
- int (*setMaterial)(int matnr, void *attribs), bool wireframe, bool fast);
-void BKE_pbvh_draw_BB(PBVH *bvh);
+void BKE_pbvh_draw_cb(
+ PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, bool only_mask,
+ void (*draw_fn)(void *user_data, struct GPUBatch *batch), void *user_data);
/* PBVH Access */
typedef enum {
@@ -155,6 +155,8 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden,
/* multires level, only valid for type == PBVH_GRIDS */
void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key);
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh, int *num_grids);
+
/* Only valid for type == PBVH_BMESH */
struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh);
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
@@ -219,7 +221,7 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node);
void BKE_pbvh_bmesh_after_stroke(PBVH *bvh);
-/* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */
+/* Update Normals/Bounding Box/Redraw and clear flags */
void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
@@ -238,7 +240,7 @@ void BKE_pbvh_node_layer_disp_free(PBVHNode *node);
/* vertex deformer */
float (*BKE_pbvh_get_vertCos(struct PBVH *pbvh))[3];
-void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]);
+void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3], const int totvert);
bool BKE_pbvh_isDeformed(struct PBVH *pbvh);
/* Vertex Iterator */
@@ -367,6 +369,7 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *bvh, PBVHNode *node);
//void BKE_pbvh_node_BB_reset(PBVHNode *node);
//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]);
+bool pbvh_has_mask(PBVH *bvh);
void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color);
void pbvh_show_mask_set(PBVH *bvh, bool show_mask);
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index e905a5efae4..7456a4bfb15 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -90,6 +90,7 @@ struct ParticleKey;
struct ParticleSystem;
struct PointCache;
struct Scene;
+struct ViewLayer;
struct SmokeModifierData;
struct SoftBody;
struct RigidBodyWorld;
@@ -186,6 +187,8 @@ typedef struct PTCacheID {
typedef struct PTCacheBaker {
struct Main *bmain;
struct Scene *scene;
+ struct ViewLayer *view_layer;
+ struct Depsgraph *depsgraph;
int bake;
int render;
int anim_init;
@@ -243,13 +246,25 @@ typedef struct PTCacheUndo {
size_t undo_size;
} PTCacheUndo;
+enum {
+ /* Modifier stack got evaluated during particle edit mode, need to copy
+ * new evaluated particles to the edit struct.
+ */
+ PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL = (1 << 0),
+};
+
typedef struct PTCacheEdit {
+ int flags;
+
PTCacheEditPoint *points;
struct PTCacheID pid;
/* particles stuff */
struct ParticleSystem *psys;
+ struct ParticleSystem *psys_eval;
+ struct ParticleSystemModifierData *psmd;
+ struct ParticleSystemModifierData *psmd_eval;
struct KDTree *emitter_field;
float *emitter_cosnos; /* localspace face centers and normals (average of its verts), from the derived mesh */
int *mirror_cache;
@@ -274,8 +289,9 @@ void BKE_ptcache_id_from_smoke(PTCacheID *pid, struct Object *ob, struct SmokeMo
void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid, struct Object *ob, struct DynamicPaintSurface *surface);
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
+PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache);
void BKE_ptcache_ids_from_object(
- struct Main *bmain, struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis);
+ struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis);
/***************** Global funcs ****************************/
void BKE_ptcache_remove(void);
@@ -318,7 +334,7 @@ struct PointCache *BKE_ptcache_copy_list(struct ListBase *ptcaches_new, const st
/********************** Baking *********************/
/* Bakes cache with cache_step sized jumps in time, not accurate but very fast. */
-void BKE_ptcache_quick_cache_all(struct Main *bmain, struct Scene *scene);
+void BKE_ptcache_quick_cache_all(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer);
/* Bake cache or simulate to current frame with settings defined in the baker. */
void BKE_ptcache_bake(struct PTCacheBaker *baker);
diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h
deleted file mode 100644
index d917a6b55e6..00000000000
--- a/source/blender/blenkernel/BKE_property.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_PROPERTY_H__
-#define __BKE_PROPERTY_H__
-
-/** \file BKE_property.h
- * \ingroup bke
- */
-
-struct bProperty;
-struct ListBase;
-struct Object;
-
-void BKE_bproperty_free(struct bProperty *prop);
-void BKE_bproperty_free_list(struct ListBase *lb);
-struct bProperty *BKE_bproperty_copy(const struct bProperty *prop);
-void BKE_bproperty_copy_list(struct ListBase *lbn, const struct ListBase *lbo);
-void BKE_bproperty_init(struct bProperty *prop);
-struct bProperty *BKE_bproperty_new(int type);
-void BKE_bproperty_unique(struct bProperty *first, struct bProperty *prop, int force);
-struct bProperty *BKE_bproperty_object_get(struct Object *ob, const char *name);
-void BKE_bproperty_object_set(struct Object *ob, struct bProperty *propc);
-// int BKE_bproperty_cmp(struct bProperty *prop, const char *str);
-void BKE_bproperty_set(struct bProperty *prop, const char *str);
-void BKE_bproperty_add(struct bProperty *prop, const char *str);
-/* should really be called '_get_valstr()' or '_as_string()' */
-void BKE_bproperty_set_valstr(struct bProperty *prop, char str[MAX_PROPSTRING]);
-
-#endif
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 470aae40df9..1fa8106d63b 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -37,14 +37,15 @@
struct RigidBodyWorld;
struct RigidBodyOb;
+struct Depsgraph;
struct Scene;
struct Object;
/* -------------- */
/* Memory Management */
-void BKE_rigidbody_free_world(struct RigidBodyWorld *rbw);
-void BKE_rigidbody_free_object(struct Object *ob);
+void BKE_rigidbody_free_world(struct Scene *scene);
+void BKE_rigidbody_free_object(struct Object *ob, struct RigidBodyWorld *rbw);
void BKE_rigidbody_free_constraint(struct Object *ob);
/* ...... */
@@ -79,7 +80,7 @@ void BKE_rigidbody_calc_center_of_mass(struct Object *ob, float r_center[3]);
/* Utilities */
struct RigidBodyWorld *BKE_rigidbody_get_world(struct Scene *scene);
-void BKE_rigidbody_remove_object(struct Scene *scene, struct Object *ob);
+void BKE_rigidbody_remove_object(struct Main *bmain, struct Scene *scene, struct Object *ob);
void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob);
/* -------------- */
@@ -99,21 +100,19 @@ void BKE_rigidbody_aftertrans_update(struct Object *ob, float loc[3], float rot[
void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
bool BKE_rigidbody_check_sim_running(struct RigidBodyWorld *rbw, float ctime);
void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
-void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime);
-void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime);
+void BKE_rigidbody_rebuild_world(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
+void BKE_rigidbody_do_simulation(struct Depsgraph *depsgraph, struct Scene *scene, float ctime);
/* -------------------- */
/* Depsgraph evaluation */
-struct EvaluationContext;
-
-void BKE_rigidbody_rebuild_sim(struct EvaluationContext *eval_ctx,
+void BKE_rigidbody_rebuild_sim(struct Depsgraph *depsgraph,
struct Scene *scene);
-void BKE_rigidbody_eval_simulation(struct EvaluationContext *eval_ctx,
+void BKE_rigidbody_eval_simulation(struct Depsgraph *depsgraph,
struct Scene *scene);
-void BKE_rigidbody_object_sync_transforms(struct EvaluationContext *eval_ctx,
+void BKE_rigidbody_object_sync_transforms(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
deleted file mode 100644
index 653fc1afa64..00000000000
--- a/source/blender/blenkernel/BKE_sca.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_SCA_H__
-#define __BKE_SCA_H__
-
-/** \file BKE_sca.h
- * \ingroup bke
- */
-
-struct Main;
-struct Object;
-struct bSensor;
-struct bController;
-struct bActuator;
-
-void link_logicbricks(void **poin, void ***ppoin, short *tot, short size);
-void unlink_logicbricks(void **poin, void ***ppoin, short *tot);
-
-void unlink_controller(struct bController *cont);
-void unlink_controllers(struct ListBase *lb);
-void free_controller(struct bController *cont);
-void free_controllers(struct ListBase *lb);
-
-void unlink_actuator(struct bActuator *act);
-void unlink_actuators(struct ListBase *lb);
-void free_actuator(struct bActuator *act);
-void free_actuators(struct ListBase *lb);
-
-void free_sensor(struct bSensor *sens);
-void free_sensors(struct ListBase *lb);
-struct bSensor *copy_sensor(struct bSensor *sens, const int flag);
-void copy_sensors(struct ListBase *lbn, const struct ListBase *lbo, const int flag);
-void init_sensor(struct bSensor *sens);
-struct bSensor *new_sensor(int type);
-struct bController *copy_controller(struct bController *cont, const int flag);
-void copy_controllers(struct ListBase *lbn, const struct ListBase *lbo, const int flag);
-void init_controller(struct bController *cont);
-struct bController *new_controller(int type);
-struct bActuator *copy_actuator(struct bActuator *act, const int flag);
-void copy_actuators(struct ListBase *lbn, const struct ListBase *lbo, const int flag);
-void init_actuator(struct bActuator *act);
-struct bActuator *new_actuator(int type);
-void clear_sca_new_poins_ob(struct Object *ob);
-void clear_sca_new_poins(void);
-void set_sca_new_poins_ob(struct Object *ob);
-void set_sca_new_poins(void);
-
-void BKE_sca_logic_links_remap(struct Main *bmain, struct Object *ob_old, struct Object *ob_new);
-void BKE_sca_logic_copy(struct Object *ob_new, const struct Object *ob, const int flag);
-
-void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up);
-void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up);
-void sca_move_actuator(struct bActuator *act_to_move, struct Object *ob, int move_up);
-
-/* Callback format for performing operations on ID-pointers for sensors/controllers/actuators. */
-typedef void (*SCASensorIDFunc)(struct bSensor *sensor, struct ID **idpoin, void *userdata, int cb_flag);
-typedef void (*SCAControllerIDFunc)(struct bController *controller, struct ID **idpoin, void *userdata, int cb_flag);
-typedef void (*SCAActuatorIDFunc)(struct bActuator *actuator, struct ID **idpoin, void *userdata, int cb_flag);
-
-void BKE_sca_sensors_id_loop(struct ListBase *senslist, SCASensorIDFunc func, void *userdata);
-void BKE_sca_controllers_id_loop(struct ListBase *contlist, SCAControllerIDFunc func, void *userdata);
-void BKE_sca_actuators_id_loop(struct ListBase *atclist, SCAActuatorIDFunc func, void *userdata);
-
-
-const char *sca_state_name_get(Object *ob, short bit);
-
-#endif
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index e85867fcbe7..e7a26afadf5 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -38,43 +38,55 @@ extern "C" {
#endif
struct AviCodecData;
-struct Base;
-struct EvaluationContext;
+struct Collection;
+struct Depsgraph;
struct Main;
struct Object;
struct RenderData;
-struct SceneRenderLayer;
struct Scene;
+struct ViewLayer;
struct UnitSettings;
-struct Main;
-
-#define SCE_COPY_NEW 0
-#define SCE_COPY_EMPTY 1
-#define SCE_COPY_LINK_OB 2
-#define SCE_COPY_LINK_DATA 3
-#define SCE_COPY_FULL 4
+struct ViewRender;
+struct WorkSpace;
+struct TransformOrientation;
+
+typedef enum eSceneCopyMethod {
+ SCE_COPY_NEW = 0,
+ SCE_COPY_EMPTY = 1,
+ SCE_COPY_LINK_OB = 2,
+ SCE_COPY_LINK_DATA = 3,
+ SCE_COPY_FULL = 4,
+} eSceneCopyMethod;
/* Use as the contents of a 'for' loop: for (SETLOOPER(...)) { ... */
#define SETLOOPER(_sce_basis, _sce_iter, _base) \
- _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, NULL); \
+ _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, BKE_view_layer_context_active_PLACEHOLDER(_sce_basis), NULL); \
_base; \
- _base = _setlooper_base_step(&_sce_iter, _base)
+ _base = _setlooper_base_step(&_sce_iter, NULL, _base)
-struct Base *_setlooper_base_step(struct Scene **sce_iter, struct Base *base);
+#define SETLOOPER_VIEW_LAYER(_sce_basis, _view_layer, _sce_iter, _base) \
+ _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, _view_layer, NULL); \
+ _base; \
+ _base = _setlooper_base_step(&_sce_iter, NULL, _base)
+
+#define SETLOOPER_SET_ONLY(_sce_basis, _sce_iter, _base) \
+ _sce_iter = _sce_basis, _base = _setlooper_base_step(&_sce_iter, NULL, NULL); \
+ _base; \
+ _base = _setlooper_base_step(&_sce_iter, NULL, _base)
+
+struct Base *_setlooper_base_step(struct Scene **sce_iter, struct ViewLayer *view_layer, struct Base *base);
void free_avicodecdata(struct AviCodecData *acd);
+void BKE_scene_free_ex(struct Scene *sce, const bool do_id_user);
void BKE_scene_free(struct Scene *sce);
void BKE_scene_init(struct Scene *sce);
struct Scene *BKE_scene_add(struct Main *bmain, const char *name);
-/* base functions */
-struct Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name);
-struct Base *BKE_scene_base_find(struct Scene *scene, struct Object *ob);
-struct Base *BKE_scene_base_add(struct Scene *sce, struct Object *ob);
-void BKE_scene_base_unlink(struct Scene *sce, struct Base *base);
-void BKE_scene_base_deselect_all(struct Scene *sce);
-void BKE_scene_base_select(struct Scene *sce, struct Base *selbase);
+void BKE_scene_remove_rigidbody_object(struct Main *bmain, struct Scene *scene, struct Object *ob);
+
+bool BKE_scene_object_find(struct Scene *scene, struct Object *ob);
+struct Object *BKE_scene_object_find_by_name(struct Scene *scene, const char *name);
/* Scene base iteration function.
* Define struct here, so no need to bother with alloc/free it.
@@ -87,11 +99,14 @@ typedef struct SceneBaseIter {
int phase;
} SceneBaseIter;
-int BKE_scene_base_iter_next(struct Main *bmain, struct EvaluationContext *eval_ctx, struct SceneBaseIter *iter,
- struct Scene **scene, int val, struct Base **base, struct Object **ob);
+int BKE_scene_base_iter_next(
+ struct Depsgraph *depsgraph, struct SceneBaseIter *iter,
+ struct Scene **scene, int val, struct Base **base, struct Object **ob);
-void BKE_scene_base_flag_to_objects(struct Scene *scene);
+void BKE_scene_base_flag_to_objects(struct ViewLayer *view_layer);
void BKE_scene_base_flag_from_objects(struct Scene *scene);
+void BKE_scene_object_base_flag_sync_from_base(struct Base *base);
+void BKE_scene_object_base_flag_sync_from_object(struct Base *base);
void BKE_scene_set_background(struct Main *bmain, struct Scene *sce);
struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
@@ -105,7 +120,8 @@ void BKE_scene_groups_relink(struct Scene *sce);
void BKE_scene_make_local(struct Main *bmain, struct Scene *sce, const bool lib_local);
-struct Object *BKE_scene_camera_find(struct Scene *sc);
+struct Scene *BKE_scene_find_from_collection(const struct Main *bmain, const struct Collection *collection);
+
#ifdef DURIAN_CAMERA_SWITCH
struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH
#endif
@@ -124,12 +140,15 @@ float BKE_scene_frame_get_from_ctime(const struct Scene *scene, const float fram
void BKE_scene_frame_set(struct Scene *scene, double cfra);
/* ** Scene evaluation ** */
-void BKE_scene_update_tagged(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce);
-void BKE_scene_update_for_newframe(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay);
-void BKE_scene_update_for_newframe_ex(struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *sce, unsigned int lay, bool do_invisible_flush);
-struct SceneRenderLayer *BKE_scene_add_render_layer(struct Scene *sce, const char *name);
-bool BKE_scene_remove_render_layer(struct Main *main, struct Scene *scene, struct SceneRenderLayer *srl);
+void BKE_scene_graph_update_tagged(struct Depsgraph *depsgraph,
+ struct Main *bmain);
+
+void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph,
+ struct Main *bmain);
+
+void BKE_scene_view_layer_graph_evaluated_ensure(
+ struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer);
struct SceneRenderView *BKE_scene_add_render_view(struct Scene *sce, const char *name);
bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *srv);
@@ -137,16 +156,13 @@ bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *s
/* render profile */
int get_render_subsurf_level(const struct RenderData *r, int level, bool for_render);
int get_render_child_particle_number(const struct RenderData *r, int num, bool for_render);
-int get_render_shadow_samples(const struct RenderData *r, int samples);
-float get_render_aosss_error(const struct RenderData *r, float error);
-bool BKE_scene_use_new_shading_nodes(const struct Scene *scene);
bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
-bool BKE_scene_use_world_space_shading(struct Scene *scene);
bool BKE_scene_use_spherical_stereo(struct Scene *scene);
-bool BKE_scene_uses_blender_internal(const struct Scene *scene);
-bool BKE_scene_uses_blender_game(const struct Scene *scene);
+bool BKE_scene_uses_blender_eevee(const struct Scene *scene);
+bool BKE_scene_uses_blender_opengl(const struct Scene *scene);
+bool BKE_scene_uses_cycles(const struct Scene *scene);
void BKE_scene_disable_color_management(struct Scene *scene);
bool BKE_scene_check_color_management_enabled(const struct Scene *scene);
@@ -157,6 +173,8 @@ int BKE_render_num_threads(const struct RenderData *r);
int BKE_render_preview_pixel_size(const struct RenderData *r);
+/**********************************/
+
double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
/* multiview */
@@ -176,6 +194,20 @@ void BKE_scene_multiview_view_prefix_get(struct Scene *scene, const char
void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, const size_t width, const size_t height, size_t *r_width, size_t *r_height);
int BKE_scene_multiview_num_videos_get(const struct RenderData *rd);
+/* depsgraph */
+void BKE_scene_allocate_depsgraph_hash(struct Scene *scene);
+void BKE_scene_ensure_depsgraph_hash(struct Scene *scene);
+void BKE_scene_free_depsgraph_hash(struct Scene *scene);
+
+struct Depsgraph *BKE_scene_get_depsgraph(struct Scene *scene, struct ViewLayer *view_layer, bool allocate);
+
+void BKE_scene_transform_orientation_remove(
+ struct Scene *scene, struct TransformOrientation *orientation);
+struct TransformOrientation *BKE_scene_transform_orientation_find(
+ const struct Scene *scene, const int index);
+int BKE_scene_transform_orientation_get_index(
+ const struct Scene *scene, const struct TransformOrientation *orientation);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index b33b9e455f1..0d766e83299 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -41,18 +41,25 @@ struct Menu;
struct Panel;
struct Scene;
struct ScrArea;
+struct ScrVert;
struct SpaceType;
+struct TransformOrientation;
struct View3D;
+struct View3DShading;
struct bContext;
struct bContextDataResult;
struct bScreen;
struct uiLayout;
struct uiList;
struct wmKeyConfig;
+struct wmGizmoMap;
struct wmNotifier;
struct wmWindow;
struct wmWindowManager;
+struct WorkSpace;
struct GPUFXSettings;
+struct wmMsgBus;
+struct ScrAreaMap;
#include "BLI_compiler_attrs.h"
@@ -71,8 +78,9 @@ typedef struct SpaceType {
int spaceid; /* unique space identifier */
int iconid; /* icon lookup for menus */
- /* initial allocation, after this WM will call init() too */
- struct SpaceLink *(*new)(const struct bContext *C);
+ /* Initial allocation, after this WM will call init() too. Some editors need
+ * area and scene data (e.g. frame range) to set their initial scrolling. */
+ struct SpaceLink *(*new)(const struct ScrArea *sa, const struct Scene *scene);
/* not free spacelink itself */
void (*free)(struct SpaceLink *sl);
@@ -81,7 +89,8 @@ typedef struct SpaceType {
/* exit is called when the area is hidden or removed */
void (*exit)(struct wmWindowManager *wm, struct ScrArea *sa);
/* Listeners can react to bContext changes */
- void (*listener)(struct bScreen *sc, struct ScrArea *sa, struct wmNotifier *wmn);
+ void (*listener)(struct wmWindow *win, struct ScrArea *sa,
+ struct wmNotifier *wmn, struct Scene *scene);
/* refresh context, called after filereads, ED_area_tag_refresh() */
void (*refresh)(const struct bContext *C, struct ScrArea *sa);
@@ -96,18 +105,22 @@ typedef struct SpaceType {
/* on startup, define dropboxes for spacetype+regions */
void (*dropboxes)(void);
+ /* initialize gizmo-map-types and gizmo-group-types with the region */
+ void (*gizmos)(void);
+
/* return context data */
int (*context)(const struct bContext *C, const char *member, struct bContextDataResult *result);
/* Used when we want to replace an ID by another (or NULL). */
void (*id_remap)(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id);
+ int (*space_subtype_get)(struct ScrArea *sa);
+ void (*space_subtype_set)(struct ScrArea *sa, int value);
+ void (*space_subtype_item_extend)(struct bContext *C, EnumPropertyItem **item, int *totitem);
+
/* region type definitions */
ListBase regiontypes;
- /* tool shelf definitions */
- ListBase toolshelf;
-
/* read and write... */
/* default keymaps to add */
@@ -120,8 +133,7 @@ typedef struct SpaceType {
typedef struct ARegionType {
struct ARegionType *next, *prev;
- /* unique identifier within this space, defines RGN_TYPE_xxxx */
- int regionid;
+ int regionid; /* unique identifier within this space, defines RGN_TYPE_xxxx */
/* add handlers, stuff you only do once or on area/region type/size changes */
void (*init)(struct wmWindowManager *wm, struct ARegion *ar);
@@ -129,10 +141,21 @@ typedef struct ARegionType {
void (*exit)(struct wmWindowManager *wm, struct ARegion *ar);
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *C, struct ARegion *ar);
+ /* optional, compute button layout before drawing for dynamic size */
+ void (*layout)(const struct bContext *C, struct ARegion *ar);
+ /* snap the size of the region (can be NULL for no snapping). */
+ int (*snap_size)(const struct ARegion *ar, int size, int axis);
/* contextual changes should be handled here */
- void (*listener)(struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar, struct wmNotifier *wmn);
+ void (*listener)(struct wmWindow *win, struct ScrArea *sa, struct ARegion *ar,
+ struct wmNotifier *wmn, const struct Scene *scene);
+ /* Optional callback to generate subscriptions. */
+ void (*message_subscribe)(
+ const struct bContext *C,
+ struct WorkSpace *workspace, struct Scene *scene,
+ struct bScreen *sc, struct ScrArea *sa, struct ARegion *ar,
+ struct wmMsgBus *mbus);
- void (*free)(struct ARegion *ar);
+ void (*free)(struct ARegion *);
/* split region, copy data optionally */
void *(*duplicate)(void *poin);
@@ -179,8 +202,12 @@ typedef struct PanelType {
char translation_context[BKE_ST_MAXNAME];
char context[BKE_ST_MAXNAME]; /* for buttons window */
char category[BKE_ST_MAXNAME]; /* for category tabs */
- int space_type;
- int region_type;
+ char owner_id[BKE_ST_MAXNAME]; /* for work-spaces to selectively show. */
+ char parent_id[BKE_ST_MAXNAME]; /* parent idname for subpanels */
+ short space_type;
+ short region_type;
+ /* For popovers, 0 for default. */
+ int ui_units_x;
int flag;
@@ -188,9 +215,15 @@ typedef struct PanelType {
bool (*poll)(const struct bContext *C, struct PanelType *pt);
/* draw header (optional) */
void (*draw_header)(const struct bContext *C, struct Panel *pa);
+ /* draw header preset (optional) */
+ void (*draw_header_preset)(const struct bContext *C, struct Panel *pa);
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *C, struct Panel *pa);
+ /* sub panels */
+ struct PanelType *parent;
+ ListBase children;
+
/* RNA integration */
ExtensionRNA ext;
} PanelType;
@@ -205,7 +238,7 @@ typedef void (*uiListDrawItemFunc)(
/* Draw the filtering part of an uiList */
typedef void (*uiListDrawFilterFunc)(
- struct uiList *ui_list, struct bContext *C, struct uiLayout *layout);
+ struct uiList *ui_list, struct bContext *C, struct uiLayout *layout, bool reverse);
/* Filter items of an uiList */
typedef void (*uiListFilterItemsFunc)(
@@ -231,7 +264,9 @@ typedef struct HeaderType {
char idname[BKE_ST_MAXNAME]; /* unique name */
int space_type;
+ int region_type;
+ bool (*poll)(const struct bContext *C, struct HeaderType *ht);
/* draw entirely, view changes should be handled here */
void (*draw)(const struct bContext *C, struct Header *header);
@@ -253,6 +288,7 @@ typedef struct MenuType {
char idname[BKE_ST_MAXNAME]; /* unique name */
char label[BKE_ST_MAXNAME]; /* for button text */
char translation_context[BKE_ST_MAXNAME];
+ char owner_id[BKE_ST_MAXNAME]; /* optional, see: #wmOwnerID */
const char *description;
/* verify if the menu should draw or not */
@@ -290,35 +326,42 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID
/* area/regions */
struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar);
void BKE_area_region_free(struct SpaceType *st, struct ARegion *ar);
+void BKE_area_region_panels_free(struct ListBase *panels);
void BKE_screen_area_free(struct ScrArea *sa);
+/* Gizmo-maps of a region need to be freed with the region. Uses callback to avoid low-level call. */
+void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *));
+void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *));
struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
struct ARegion *BKE_area_find_region_xy(struct ScrArea *sa, const int regiontype, int x, int y);
struct ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min);
+struct ScrArea *BKE_screen_area_map_find_area_xy(const struct ScrAreaMap *areamap, const int spacetype, int x, int y);
struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y);
-unsigned int BKE_screen_view3d_layer_active_ex(
- const struct View3D *v3d, const struct Scene *scene, bool use_localvd) ATTR_NONNULL(2);
-unsigned int BKE_screen_view3d_layer_active(
- const struct View3D *v3d, const struct Scene *scene) ATTR_NONNULL(2);
-
-unsigned int BKE_screen_view3d_layer_all(const struct bScreen *sc) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void BKE_screen_gizmo_tag_refresh(struct bScreen *sc);
void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene);
-void BKE_screen_view3d_scene_sync(struct bScreen *sc);
-void BKE_screen_view3d_main_sync(ListBase *screen_lb, struct Scene *scene);
-void BKE_screen_view3d_twmode_remove(struct View3D *v3d, const int i);
-void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, struct Scene *scene, const int i);
-void BKE_screen_gpu_fx_validate(struct GPUFXSettings *fx_settings);
+void BKE_screen_view3d_scene_sync(struct bScreen *sc, struct Scene *scene);
+bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* zoom factor conversion */
float BKE_screen_view3d_zoom_to_fac(float camzoom);
float BKE_screen_view3d_zoom_from_fac(float zoomfac);
+void BKE_screen_view3d_shading_init(struct View3DShading *shading);
+
/* screen */
void BKE_screen_free(struct bScreen *sc);
-unsigned int BKE_screen_visible_layers(struct bScreen *screen, struct Scene *scene);
+void BKE_screen_area_map_free(struct ScrAreaMap *area_map) ATTR_NONNULL();
+
+struct ScrEdge *BKE_screen_find_edge(struct bScreen *sc, struct ScrVert *v1, struct ScrVert *v2);
+void BKE_screen_sort_scrvert(struct ScrVert **v1, struct ScrVert **v2);
+void BKE_screen_remove_double_scrverts(struct bScreen *sc);
+void BKE_screen_remove_double_scredges(struct bScreen *sc);
+void BKE_screen_remove_unused_scredges(struct bScreen *sc);
+void BKE_screen_remove_unused_scrverts(struct bScreen *sc);
-#endif /* __BKE_SCREEN_H__ */
+#endif
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index c408597de32..00fd4ded8c6 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -31,7 +31,7 @@
*/
struct bContext;
-struct EvaluationContext;
+struct Depsgraph;
struct StripColorBalance;
struct Editing;
struct GSet;
@@ -40,6 +40,7 @@ struct GPUFX;
struct ImBuf;
struct Main;
struct Mask;
+struct RenderEngineType;
struct Scene;
struct Sequence;
struct SequenceModifierData;
@@ -92,12 +93,13 @@ void BKE_sequence_iterator_end(SeqIterator *iter);
}
typedef struct SeqRenderData {
- struct EvaluationContext *eval_ctx;
struct Main *bmain;
+ struct Depsgraph *depsgraph;
struct Scene *scene;
int rectx;
int recty;
int preview_render_size;
+ int for_render;
int motion_blur_samples;
float motion_blur_shutter;
bool skip_cache;
@@ -112,8 +114,9 @@ typedef struct SeqRenderData {
} SeqRenderData;
void BKE_sequencer_new_render_data(
- struct EvaluationContext *eval_ctx, struct Main *bmain, struct Scene *scene,
+ struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene,
int rectx, int recty, int preview_render_size,
+ int for_render,
SeqRenderData *r_context);
int BKE_sequencer_cmp_time_startdisp(const void *a, const void *b);
@@ -249,7 +252,7 @@ struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change);
bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, struct Sequence *seq, float cfra);
-void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue);
+void BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Sequence *seq, struct GSet *file_list, ListBase *queue);
void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context, short *stop, short *do_update, float *progress);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
@@ -434,11 +437,12 @@ enum {
};
typedef struct ImBuf *(*SequencerDrawView)(
- struct Main *bmain, struct Scene *scene,
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ int drawtype,
struct Object *camera, int width, int height,
- unsigned int flag, unsigned int draw_flags, int drawtype, int alpha_mode,
+ unsigned int flag, unsigned int draw_flags, int alpha_mode,
int samples, const char *viewname,
- struct GPUFX *fx, struct GPUOffScreen *ofs, char err_out[256]);
+ struct GPUOffScreen *ofs, char err_out[256]);
extern SequencerDrawView sequencer_view3d_cb;
/* copy/paste */
diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h
new file mode 100644
index 00000000000..3306d8256e8
--- /dev/null
+++ b/source/blender/blenkernel/BKE_shader_fx.h
@@ -0,0 +1,180 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is: all of this file.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#ifndef __BKE_SHADER_FX_H__
+#define __BKE_SHADER_FX_H__
+
+/** \file BKE_shader_fx.h
+ * \ingroup bke
+ */
+
+#include "DNA_shader_fx_types.h" /* needed for all enum typdefs */
+#include "BLI_compiler_attrs.h"
+#include "BKE_customdata.h"
+
+struct ID;
+struct Depsgraph;
+struct DerivedMesh;
+struct Mesh;
+struct Object;
+struct Scene;
+struct ViewLayer;
+struct ListBase;
+struct bArmature;
+struct Main;
+struct ShaderFxData;
+struct DepsNodeHandle;
+struct bGPDlayer;
+struct bGPDframe;
+struct bGPDstroke;
+struct ModifierUpdateDepsgraphContext;
+
+#define SHADER_FX_ACTIVE(_fx, _is_render) (((_fx->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
+ ((_fx->mode & eShaderFxMode_Render) && (_is_render == true)))
+#define SHADER_FX_EDIT(_fx, _is_edit) (((_fx->mode & eShaderFxMode_Editmode) == 0) && (_is_edit))
+
+typedef enum {
+ /* Should not be used, only for None type */
+ eShaderFxType_NoneType,
+
+ /* grease pencil effects */
+ eShaderFxType_GpencilType,
+} ShaderFxTypeType;
+
+typedef enum {
+ eShaderFxTypeFlag_SupportsEditmode = (1 << 0),
+
+ /* For effects that support editmode this determines if the
+ * effect should be enabled by default in editmode.
+ */
+ eShaderFxTypeFlag_EnableInEditmode = (1 << 2),
+
+ /* max one per type */
+ eShaderFxTypeFlag_Single = (1 << 4),
+
+ /* can't be added manually by user */
+ eShaderFxTypeFlag_NoUserAdd = (1 << 5),
+} ShaderFxTypeFlag;
+
+/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
+typedef void(*ShaderFxObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
+typedef void(*ShaderFxIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
+typedef void(*ShaderFxTexWalkFunc)(void *userData, struct Object *ob, struct ShaderFxData *fx, const char *propname);
+
+typedef struct ShaderFxTypeInfo {
+ /* The user visible name for this effect */
+ char name[32];
+
+ /* The DNA struct name for the effect data type, used to
+ * write the DNA data out.
+ */
+ char struct_name[32];
+
+ /* The size of the effect data type, used by allocation. */
+ int struct_size;
+
+ ShaderFxTypeType type;
+ ShaderFxTypeFlag flags;
+
+ /* Copy instance data for this effect type. Should copy all user
+ * level settings to the target effect.
+ */
+ void(*copyData)(const struct ShaderFxData *fx, struct ShaderFxData *target);
+
+ /* Initialize new instance data for this effect type, this function
+ * should set effect variables to their default values.
+ *
+ * This function is optional.
+ */
+ void (*initData)(struct ShaderFxData *fx);
+
+ /* Free internal effect data variables, this function should
+ * not free the fx variable itself.
+ *
+ * This function is optional.
+ */
+ void (*freeData)(struct ShaderFxData *fx);
+
+ /* Return a boolean value indicating if this effect is able to be
+ * calculated based on the effect data. This is *not* regarding the
+ * fx->flag, that is tested by the system, this is just if the data
+ * validates (for example, a lattice will return false if the lattice
+ * object is not defined).
+ *
+ * This function is optional (assumes never disabled if not present).
+ */
+ bool (*isDisabled)(struct ShaderFxData *fx, int userRenderParams);
+
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ void (*updateDepsgraph)(struct ShaderFxData *fx,
+ const struct ModifierUpdateDepsgraphContext *ctx);
+
+ /* Should return true if the effect needs to be recalculated on time
+ * changes.
+ *
+ * This function is optional (assumes false if not present).
+ */
+ bool (*dependsOnTime)(struct ShaderFxData *fx);
+
+
+ /* Should call the given walk function on with a pointer to each Object
+ * pointer that the effect data stores. This is used for linking on file
+ * load and for unlinking objects or forwarding object references.
+ *
+ * This function is optional.
+ */
+ void (*foreachObjectLink)(struct ShaderFxData *fx, struct Object *ob,
+ ShaderFxObjectWalkFunc walk, void *userData);
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the effect data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional. If it is not present, foreachObjectLink
+ * will be used.
+ */
+ void (*foreachIDLink)(struct ShaderFxData *fx, struct Object *ob,
+ ShaderFxIDWalkFunc walk, void *userData);
+} ShaderFxTypeInfo;
+
+/* Initialize global data (type info and some common global storages). */
+void BKE_shaderfx_init(void);
+
+const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_new(int type);
+void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
+void BKE_shaderfx_free(struct ShaderFxData *fx);
+bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
+bool BKE_shaderfx_dependsOnTime(struct ShaderFxData *fx);
+struct ShaderFxData *BKE_shaderfx_findByType(struct Object *ob, ShaderFxType type);
+struct ShaderFxData *BKE_shaderfx_findByName(struct Object *ob, const char *name);
+void BKE_shaderfx_copyData_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
+void BKE_shaderfx_copyData(struct ShaderFxData *fx, struct ShaderFxData *target);
+void BKE_shaderfx_copyData_ex(struct ShaderFxData *fx, struct ShaderFxData *target, const int flag);
+void BKE_shaderfx_foreachIDLink(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
+
+bool BKE_shaderfx_has_gpencil(struct Object *ob);
+
+#endif /* __BKE_SHADER_FX_H__ */
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 31b4b5cecc5..04c0f1c5d9a 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -33,6 +33,7 @@
/* Shrinkwrap stuff */
#include "BKE_bvhutils.h"
+#include "BLI_bitmap.h"
/*
* Shrinkwrap is composed by a set of functions and options that define the type of shrink.
@@ -47,37 +48,64 @@
*/
struct Object;
-struct DerivedMesh;
+struct Mesh;
struct MVert;
struct MDeformVert;
+struct ModifierEvalContext;
struct ShrinkwrapModifierData;
-struct MDeformVert;
struct BVHTree;
struct SpaceTransform;
+/* Information about boundary edges in the mesh. */
+typedef struct ShrinkwrapBoundaryVertData {
+ /* Average direction of edges that meet here. */
+ float direction[3];
+
+ /* Closest vector to direction that is orthogonal to vertex normal. */
+ float normal_plane[3];
+} ShrinkwrapBoundaryVertData;
+
+typedef struct ShrinkwrapBoundaryData {
+ /* True if the edge belongs to exactly one face. */
+ const BLI_bitmap *edge_is_boundary;
+ /* True if the looptri has any boundary edges. */
+ const BLI_bitmap *looptri_has_boundary;
+
+ /* Mapping from vertex index to boundary vertex index, or -1.
+ * Used for compact storage of data about boundary vertices. */
+ const int *vert_boundary_id;
+ unsigned int num_boundary_verts;
+
+ /* Direction data about boundary vertices. */
+ const ShrinkwrapBoundaryVertData *boundary_verts;
+} ShrinkwrapBoundaryData;
-typedef struct ShrinkwrapCalcData {
- ShrinkwrapModifierData *smd; //shrinkwrap modifier data
+void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh);
+void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh);
- struct Object *ob; //object we are applying shrinkwrap to
+/* Information about a mesh and BVH tree. */
+typedef struct ShrinkwrapTreeData {
+ Mesh *mesh;
- struct MVert *vert; //Array of verts being projected (to fetch normals or other data)
- float (*vertexCos)[3]; //vertexs being shrinkwraped
- int numVerts;
+ BVHTree *bvh;
+ BVHTreeFromMesh treeData;
- struct MDeformVert *dvert; //Pointer to mdeform array
- int vgroup; //Vertex group num
- bool invert_vgroup; /* invert vertex group influence */
+ float (*clnors)[3];
+ ShrinkwrapBoundaryData *boundary;
+} ShrinkwrapTreeData;
- struct DerivedMesh *target; //mesh we are shrinking to
- struct SpaceTransform local2target; //transform to move between local and target space
+/* Checks if the modifier needs target normals with these settings. */
+bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode);
- float keepDist; //Distance to keep above target surface (units are in local space)
+/* Initializes the mesh data structure from the given mesh and settings. */
+bool BKE_shrinkwrap_init_tree(struct ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals);
-} ShrinkwrapCalcData;
+/* Frees the tree data if necessary. */
+void BKE_shrinkwrap_free_tree(struct ShrinkwrapTreeData *data);
-void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts, bool for_render);
+/* Implementation of the Shrinkwrap modifier */
+void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Scene *scene, struct Object *ob, struct Mesh *mesh,
+ float (*vertexCos)[3], int numVerts);
/*
* This function casts a ray in the given BVHTree.. but it takes into consideration the space_transform, that is:
@@ -91,8 +119,22 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object
*/
bool BKE_shrinkwrap_project_normal(
char options, const float vert[3], const float dir[3], const float ray_radius,
- const struct SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit,
- BVHTree_RayCastCallback callback, void *userdata);
+ const struct SpaceTransform *transf, struct ShrinkwrapTreeData *tree, BVHTreeRayHit *hit);
+
+/* Maps the point to the nearest surface, either by simple nearest, or by target normal projection. */
+void BKE_shrinkwrap_find_nearest_surface(
+ struct ShrinkwrapTreeData *tree, struct BVHTreeNearest *nearest, float co[3], int type);
+
+/* Computes a smooth normal of the target (if applicable) at the hit location. */
+void BKE_shrinkwrap_compute_smooth_normal(
+ const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
+ int looptri_idx, const float hit_co[3], const float hit_no[3], float r_no[3]);
+
+/* Apply the shrink to surface modes to the given original coordinates and nearest point. */
+void BKE_shrinkwrap_snap_point_to_surface(
+ const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
+ int mode, int hit_idx, const float hit_co[3], const float hit_no[3], float goal_dist,
+ const float point_co[3], float r_point_co[3]);
/*
* NULL initializers to local data
diff --git a/source/blender/blenkernel/BKE_sketch.h b/source/blender/blenkernel/BKE_sketch.h
deleted file mode 100644
index 9b9c125fbe6..00000000000
--- a/source/blender/blenkernel/BKE_sketch.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#ifndef __BKE_SKETCH_H__
-#define __BKE_SKETCH_H__
-
-/** \file BKE_sketch.h
- * \ingroup bke
- */
-
-typedef enum SK_PType {
- PT_CONTINUOUS,
- PT_EXACT,
-} SK_PType;
-
-typedef enum SK_PMode {
- PT_SNAP,
- PT_PROJECT,
-} SK_PMode;
-
-typedef struct SK_Point {
- float p[3];
- short p2d[2];
- float no[3];
- float size;
- SK_PType type;
- SK_PMode mode;
-} SK_Point;
-
-typedef struct SK_Stroke {
- struct SK_Stroke *next, *prev;
-
- SK_Point *points;
- int nb_points;
- int buf_size;
- int selected;
-} SK_Stroke;
-
-#define SK_OVERDRAW_LIMIT 5
-
-typedef struct SK_Overdraw {
- SK_Stroke *target;
- int start, end;
- int count;
-} SK_Overdraw;
-
-#define SK_Stroke_BUFFER_INIT_SIZE 20
-
-typedef struct SK_DrawData {
- int mval[2];
- int previous_mval[2];
- SK_PType type;
-} SK_DrawData;
-
-typedef struct SK_Intersection {
- struct SK_Intersection *next, *prev;
- SK_Stroke *stroke;
- int before;
- int after;
- int gesture_index;
- float p[3];
- float lambda; /* used for sorting intersection points */
-} SK_Intersection;
-
-typedef struct SK_Sketch {
- ListBase strokes;
- SK_Stroke *active_stroke;
- SK_Stroke *gesture;
- SK_Point next_point;
- SK_Overdraw over;
-} SK_Sketch;
-
-
-typedef struct SK_Gesture {
- SK_Stroke *stk;
- SK_Stroke *segments;
-
- ListBase intersections;
- ListBase self_intersections;
-
- int nb_self_intersections;
- int nb_intersections;
- int nb_segments;
-} SK_Gesture;
-
-
-/************************************************/
-
-void freeSketch(SK_Sketch *sketch);
-SK_Sketch *createSketch(void);
-
-void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk);
-
-void sk_freeStroke(SK_Stroke *stk);
-SK_Stroke *sk_createStroke(void);
-
-SK_Point *sk_lastStrokePoint(SK_Stroke *stk);
-
-void sk_allocStrokeBuffer(SK_Stroke *stk);
-void sk_shrinkStrokeBuffer(SK_Stroke *stk);
-void sk_growStrokeBuffer(SK_Stroke *stk);
-void sk_growStrokeBufferN(SK_Stroke *stk, int n);
-
-void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n);
-void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n);
-void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt);
-void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end);
-
-void sk_trimStroke(SK_Stroke *stk, int start, int end);
-void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3]);
-void sk_polygonizeStroke(SK_Stroke *stk, int start, int end);
-void sk_flattenStroke(SK_Stroke *stk, int start, int end);
-void sk_reverseStroke(SK_Stroke *stk);
-
-void sk_filterLastContinuousStroke(SK_Stroke *stk);
-void sk_filterStroke(SK_Stroke *stk, int start, int end);
-
-void sk_initPoint(SK_Point *pt, SK_DrawData *dd, const float no[3]);
-void sk_copyPoint(SK_Point *dst, SK_Point *src);
-
-int sk_stroke_filtermval(SK_DrawData *dd);
-void sk_endContinuousStroke(SK_Stroke *stk);
-
-void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk);
-
-void sk_initDrawData(SK_DrawData *dd, const int mval[2]);
-
-void sk_deleteSelectedStrokes(SK_Sketch *sketch);
-void sk_selectAllSketch(SK_Sketch *sketch, int mode);
-
-#endif
diff --git a/source/blender/blenkernel/BKE_smoke.h b/source/blender/blenkernel/BKE_smoke.h
index a54d50cb154..deee85c02d4 100644
--- a/source/blender/blenkernel/BKE_smoke.h
+++ b/source/blender/blenkernel/BKE_smoke.h
@@ -35,7 +35,10 @@
typedef float (*bresenham_callback)(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-struct DerivedMesh *smokeModifier_do(struct SmokeModifierData *smd, struct Scene *scene, struct Object *ob, struct DerivedMesh *dm);
+struct Mesh *smokeModifier_do(
+ struct SmokeModifierData *smd, struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob, struct Mesh *me);
void smoke_reallocate_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
void smoke_reallocate_highres_fluid(struct SmokeDomainSettings *sds, float dx, int res[3], int free_old);
@@ -43,7 +46,7 @@ void smokeModifier_free(struct SmokeModifierData *smd);
void smokeModifier_reset(struct SmokeModifierData *smd);
void smokeModifier_reset_turbulence(struct SmokeModifierData *smd);
void smokeModifier_createType(struct SmokeModifierData *smd);
-void smokeModifier_copy(const SmokeModifierData *smd, struct SmokeModifierData *tsmd);
+void smokeModifier_copy(const SmokeModifierData *smd, struct SmokeModifierData *tsmd, const int flag);
float smoke_get_velocity_at(struct Object *ob, float position[3], float velocity[3]);
int smoke_get_data_flags(struct SmokeDomainSettings *sds);
diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h
index 5e8ea89c0f4..b173c995727 100644
--- a/source/blender/blenkernel/BKE_softbody.h
+++ b/source/blender/blenkernel/BKE_softbody.h
@@ -31,6 +31,7 @@
* \ingroup bke
*/
+struct Depsgraph;
struct Object;
struct Scene;
struct SoftBody;
@@ -53,13 +54,14 @@ typedef struct BodyPoint {
extern struct SoftBody *sbNew(struct Scene *scene);
/* frees internal data and softbody itself */
-extern void sbFree(struct SoftBody *sb);
+extern void sbFree(struct Object *ob);
/* frees simulation data to reset simulation */
extern void sbFreeSimulation(struct SoftBody *sb);
/* do one simul step, reading and writing vertex locs from given array */
-extern void sbObjectStep(struct Scene *scene, struct Object *ob, float framnr, float (*vertexCos)[3], int numVerts);
+extern void sbObjectStep(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
+ float framnr, float (*vertexCos)[3], int numVerts);
/* makes totally fresh start situation, resets time */
extern void sbObjectToSoftbody(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 6f8274fabc8..98fb4f47339 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -35,8 +35,8 @@
#define SOUND_WAVE_SAMPLES_PER_SECOND 250
-#ifdef WITH_SYSTEM_AUDASPACE
-# include AUD_DEVICE_H
+#if defined(WITH_AUDASPACE)
+# include <AUD_Device.h>
#endif
struct bSound;
@@ -84,7 +84,7 @@ void BKE_sound_copy_data(struct Main *bmain, struct bSound *sound_dst, const str
void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool lib_local);
-#if defined(__AUD_C_API_H__) || defined(WITH_SYSTEM_AUDASPACE)
+#if defined(WITH_AUDASPACE)
AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
#endif
@@ -149,6 +149,4 @@ float BKE_sound_get_length(struct bSound *sound);
char **BKE_sound_get_device_names(void);
-bool BKE_sound_is_jack_supported(void);
-
#endif /* __BKE_SOUND_H__ */
diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h
new file mode 100644
index 00000000000..4a7f29d7190
--- /dev/null
+++ b/source/blender/blenkernel/BKE_studiolight.h
@@ -0,0 +1,156 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006-2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BKE_STUDIOLIGHT_H__
+#define __BKE_STUDIOLIGHT_H__
+
+/** \file BKE_studiolight.h
+ * \ingroup bke
+ *
+ * Studio lighting for the 3dview
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_sys_types.h"
+
+#include "DNA_space_types.h"
+
+#include "IMB_imbuf_types.h"
+
+/*
+ * These defines are the indexes in the StudioLight.diffuse_light
+ * X_POS means the light that is traveling towards the positive X
+ * So Light direction.
+ */
+#define STUDIOLIGHT_X_POS 0
+#define STUDIOLIGHT_X_NEG 1
+#define STUDIOLIGHT_Y_POS 2
+#define STUDIOLIGHT_Y_NEG 3
+#define STUDIOLIGHT_Z_POS 4
+#define STUDIOLIGHT_Z_NEG 5
+
+#define STUDIOLIGHT_ICON_ID_TYPE_RADIANCE (1 << 0)
+#define STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE (1 << 1)
+#define STUDIOLIGHT_ICON_ID_TYPE_MATCAP (1 << 2)
+#define STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED (1 << 3)
+
+#define STUDIOLIGHT_ICON_SIZE 96
+
+#define STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL 2
+#define STUDIOLIGHT_SPHERICAL_HARMONICS_MAX_COMPONENTS 18
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 0
+# define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 1
+#endif
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 1
+# define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 4
+#endif
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 2
+# define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 9
+# define STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING_TARGET_LAMPLACIAN 10.0f
+#endif
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 4
+# define STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS 18
+#endif
+struct GPUTexture;
+struct StudioLight;
+
+/* StudioLight.flag */
+enum StudioLightFlag {
+ STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED = (1 << 0),
+ STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED = (1 << 1),
+ STUDIOLIGHT_INTERNAL = (1 << 2),
+ STUDIOLIGHT_EXTERNAL_FILE = (1 << 3),
+ STUDIOLIGHT_USER_DEFINED = (1 << 12),
+ STUDIOLIGHT_ORIENTATION_CAMERA = (1 << 4),
+ STUDIOLIGHT_ORIENTATION_WORLD = (1 << 5),
+ STUDIOLIGHT_ORIENTATION_VIEWNORMAL = (1 << 6),
+ STUDIOLIGHT_EXTERNAL_IMAGE_LOADED = (1 << 7),
+ STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED = (1 << 8),
+ STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE = (1 << 9),
+ STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE = (1 << 10),
+ STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11),
+ STUDIOLIGHT_UI_EXPANDED = (1 << 13),
+};
+
+#define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE)
+#define STUDIOLIGHT_FLAG_ORIENTATIONS (STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_VIEWNORMAL)
+#define STUDIOLIGHT_ORIENTATIONS_MATERIAL_MODE (STUDIOLIGHT_ORIENTATION_WORLD)
+#define STUDIOLIGHT_ORIENTATIONS_SOLID (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD)
+
+typedef void StudioLightFreeFunction(struct StudioLight *, void *data);
+
+typedef struct StudioLight {
+ struct StudioLight *next, *prev;
+
+ int index;
+ int flag;
+ char name[FILE_MAXFILE];
+ char path[FILE_MAX];
+ char *path_irr_cache;
+ char *path_sh_cache;
+ int icon_id_irradiance;
+ int icon_id_radiance;
+ int icon_id_matcap;
+ int icon_id_matcap_flipped;
+ float spherical_harmonics_coefs[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS][3];
+ float light_direction[3];
+ ImBuf *equirectangular_radiance_buffer;
+ ImBuf *equirectangular_irradiance_buffer;
+ ImBuf *radiance_cubemap_buffers[6];
+ struct GPUTexture *equirectangular_radiance_gputexture;
+ struct GPUTexture *equirectangular_irradiance_gputexture;
+ float *gpu_matcap_3components; /* 3 channel buffer for GPU_R11F_G11F_B10F */
+
+ /*
+ * Free function to clean up the running icons previews (wmJob) the usage is in
+ * interface_icons. Please be aware that this was build to handle only one free function
+ * that cleans up all icons. just to keep the code simple.
+ */
+ StudioLightFreeFunction *free_function;
+ void *free_function_data;
+} StudioLight;
+
+void BKE_studiolight_init(void);
+void BKE_studiolight_free(void);
+struct StudioLight *BKE_studiolight_find(const char *name, int flag);
+struct StudioLight *BKE_studiolight_findindex(int index, int flag);
+struct StudioLight *BKE_studiolight_find_first(int flag);
+void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type);
+struct ListBase *BKE_studiolight_listbase(void);
+void BKE_studiolight_ensure_flag(StudioLight *sl, int flag);
+void BKE_studiolight_refresh(void);
+StudioLight *BKE_studiolight_new(const char *path, int orientation);
+void BKE_studiolight_remove(StudioLight *sl);
+void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data);
+void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id);
+
+#endif /* __BKE_STUDIOLIGHT_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
new file mode 100644
index 00000000000..0a09d3528b4
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -0,0 +1,237 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv.h
+ * \ingroup bke
+ * \since July 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_H__
+#define __BKE_SUBDIV_H__
+
+#include "BLI_compiler_compat.h"
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct MultiresModifierData;
+struct Object;
+struct OpenSubdiv_Converter;
+struct OpenSubdiv_Evaluator;
+struct OpenSubdiv_TopologyRefiner;
+struct Subdiv;
+struct SubdivToMeshSettings;
+
+typedef enum eSubdivVtxBoundaryInterpolation {
+ /* Do not interpolate boundaries. */
+ SUBDIV_VTX_BOUNDARY_NONE,
+ /* Sharpen edges. */
+ SUBDIV_VTX_BOUNDARY_EDGE_ONLY,
+ /* sharpen edges and corners, */
+ SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER,
+} eSubdivVtxBoundaryInterpolation;
+
+typedef enum eSubdivFVarLinearInterpolation {
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES,
+ SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL,
+} eSubdivFVarLinearInterpolation;
+
+typedef struct SubdivSettings {
+ bool is_simple;
+ bool is_adaptive;
+ int level;
+ eSubdivVtxBoundaryInterpolation vtx_boundary_interpolation;
+ eSubdivFVarLinearInterpolation fvar_linear_interpolation;
+} SubdivSettings;
+
+/* NOTE: Order of enumerators MUST match order of values in SubdivStats. */
+typedef enum eSubdivStatsValue {
+ SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME = 0,
+ SUBDIV_STATS_SUBDIV_TO_MESH,
+ SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY,
+ SUBDIV_STATS_EVALUATOR_CREATE,
+ SUBDIV_STATS_EVALUATOR_REFINE,
+ SUBDIV_STATS_SUBDIV_TO_CCG,
+ SUBDIV_STATS_SUBDIV_TO_CCG_ELEMENTS,
+
+ NUM_SUBDIV_STATS_VALUES,
+} eSubdivStatsValue;
+
+typedef struct SubdivStats {
+ union {
+ struct {
+ /* Time spend on creating topology refiner, which includes time
+ * spend on conversion from Blender data to OpenSubdiv data, and
+ * time spend on topology orientation on OpenSubdiv C-API side.
+ */
+ double topology_refiner_creation_time;
+ /* Total time spent in BKE_subdiv_to_mesh(). */
+ double subdiv_to_mesh_time;
+ /* Geometry (MVert and co) creation time during SUBDIV_TYO_MESH. */
+ double subdiv_to_mesh_geometry_time;
+ /* Time spent on evaluator creation from topology refiner. */
+ double evaluator_creation_time;
+ /* Time spent on evaluator->refine(). */
+ double evaluator_refine_time;
+ /* Total time spent on whole CCG creation. */
+ double subdiv_to_ccg_time;
+ /* Time spent on CCG elements evaluation/initialization. */
+ double subdiv_to_ccg_elements_time;
+ };
+ double values_[NUM_SUBDIV_STATS_VALUES];
+ };
+
+ /* Per-value timestamp on when corresponding BKE_subdiv_stats_begin() was
+ * called.
+ */
+ double begin_timestamp_[NUM_SUBDIV_STATS_VALUES];
+} SubdivStats;
+
+/* Functor which evaluates dispalcement at a given (u, v) of given ptex face. */
+typedef struct SubdivDisplacement {
+ /* Return displacement which is to be added to the original coordinate.
+ *
+ * NOTE: This function is supposed to return "continuous" displacement for
+ * each pf PTex faces created for special (non-quad) polygon. This means,
+ * if displacement is stored on per-corner manner (like MDisps for multires)
+ * this is up the displacement implementation to average boundaries of the
+ * displacement grids if needed.
+ *
+ * Averaging of displacement for vertices created for over coarse vertices
+ * and edges is done by subdiv code.
+ */
+ void (*eval_displacement)(struct SubdivDisplacement *displacement,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3]);
+
+ /* Free the data, not the evaluator itself. */
+ void (*free)(struct SubdivDisplacement *displacement);
+
+ void *user_data;
+} SubdivDisplacement;
+
+/* This structure contains everything needed to construct subdivided surface.
+ * It does not specify storage, memory layout or anything else.
+ * It is possible to create different storages (like, grid based CPU side
+ * buffers, GPU subdivision mesh, CPU side fully qualified mesh) from the same
+ * Subdiv structure.
+ */
+typedef struct Subdiv {
+ /* Settings this subdivision surface is created for.
+ *
+ * It is read-only after assignment in BKE_subdiv_new_from_FOO().
+ */
+ SubdivSettings settings;
+ /* Topology refiner includes all the glue logic to feed Blender side
+ * topology to OpenSubdiv. It can be shared by both evaluator and GL mesh
+ * drawer.
+ */
+ struct OpenSubdiv_TopologyRefiner *topology_refiner;
+ /* CPU side evaluator. */
+ struct OpenSubdiv_Evaluator *evaluator;
+ /* Optional displacement evaluator. */
+ struct SubdivDisplacement *displacement_evaluator;
+ /* Statistics for debugging. */
+ SubdivStats stats;
+
+ /* Cached values, are not supposed to be accessed directly. */
+ struct {
+ /* Indexed by base face index, element indicates total number of ptex
+ *faces created for preceding base faces.
+ */
+ int *face_ptex_offset;
+ } cache_;
+} Subdiv;
+
+/* ================================ HELPERS ================================= */
+
+/* NOTE: uv_smooth is eSubsurfUVSmooth. */
+eSubdivFVarLinearInterpolation
+BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth);
+
+/* =============================== STATISTICS =============================== */
+
+void BKE_subdiv_stats_init(SubdivStats *stats);
+
+void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value);
+void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value);
+
+void BKE_subdiv_stats_print(const SubdivStats *stats);
+
+/* ============================== CONSTRUCTION ============================== */
+
+Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
+ struct OpenSubdiv_Converter *converter);
+
+Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
+ struct Mesh *mesh);
+
+void BKE_subdiv_free(Subdiv *subdiv);
+
+/* ============================ DISPLACEMENT API ============================ */
+
+void BKE_subdiv_displacement_attach_from_multires(
+ Subdiv *subdiv,
+ const struct Mesh *mesh,
+ const struct MultiresModifierData *mmd);
+
+void BKE_subdiv_displacement_detach(Subdiv *subdiv);
+
+/* ============================ TOPOLOGY HELPERS ============================ */
+
+int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv);
+
+/* ============================= VARIOUS HELPERS ============================ */
+
+/* For a given (ptex_u, ptex_v) within a ptex face get corresponding
+ * (grid_u, grid_v) within a grid.
+ */
+BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(
+ const float ptex_u, const float ptex_v,
+ float *r_grid_u, float *r_grid_v);
+
+/* For a given subdivision level (which is NOT refinement level) get size of
+ * CCG grid (number of grid points on a side).
+ */
+BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level);
+
+/* Simplified version of mdisp_rot_face_to_crn, only handles quad and
+ * works in normalized coordinates.
+ *
+ * NOTE: Output coordinates are in ptex coordinates.
+ */
+BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(
+ const float u, const float v,
+ float *r_u, float *r_v);
+
+#endif /* __BKE_SUBDIV_H__ */
+
+#include "intern/subdiv_inline.h"
diff --git a/source/blender/blenkernel/BKE_subdiv_ccg.h b/source/blender/blenkernel/BKE_subdiv_ccg.h
new file mode 100644
index 00000000000..b2aaf6fc4cc
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_ccg.h
@@ -0,0 +1,249 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv_ccg.h
+ * \ingroup bke
+ * \since July 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_CCG_H__
+#define __BKE_SUBDIV_CCG_H__
+
+#include "BKE_customdata.h"
+#include "BLI_bitmap.h"
+#include "BLI_sys_types.h"
+
+struct CCGElem;
+struct CCGFace;
+struct CCGKey;
+struct DMFlagMat;
+struct Mesh;
+struct Subdiv;
+
+/* =============================================================================
+ * Masks.
+ */
+
+/* Functor which evaluates mask value at a given (u, v) of given ptex face. */
+typedef struct SubdivCCGMask {
+ float (*eval_mask)(struct SubdivCCGMask *mask,
+ const int ptex_face_index,
+ const float u, const float v);
+
+ /* Free the data, not the evaluator itself. */
+ void (*free)(struct SubdivCCGMask *mask);
+
+ void *user_data;
+} SubdivCCGMask;
+
+/* Return true if mesh has mask and evaluator can be used. */
+bool BKE_subdiv_ccg_mask_init_from_paint(
+ SubdivCCGMask *mask_evaluator,
+ const struct Mesh *mesh);
+
+/* =============================================================================
+ * SubdivCCG.
+ */
+
+typedef struct SubdivToCCGSettings {
+ /* Resolution at which regular ptex (created for quad polygon) are being
+ * evaluated. This defines how many vertices final mesh will have: every
+ * regular ptex has resolution^2 vertices. Special (irregular, or ptex
+ * created for a corner of non-quad polygon) will have resolution of
+ * `resolution - 1`.
+ */
+ int resolution;
+ /* Denotes which extra layers to be added to CCG elements. */
+ bool need_normal;
+ bool need_mask;
+} SubdivToCCGSettings;
+
+/* This is actually a coarse face, which consists of multiple CCG grids. */
+typedef struct SubdivCCGFace {
+ /* Total number of grids in this face.
+ *
+ * This 1:1 corresponds to a number of corners (or loops) from a coarse
+ * face.
+ */
+ int num_grids;
+ /* Index of first grid from this face in SubdivCCG->grids array. */
+ int start_grid_index;
+} SubdivCCGFace;
+
+/* Definition of an edge which is adjacent to at least one of the faces. */
+typedef struct SubdivCCGAdjacentEdge {
+ int num_adjacent_faces;
+ /* Indexed by adjacent face index. */
+ SubdivCCGFace **faces;
+ /* Indexed by adjacent face index, then by point index on the edge.
+ * points to a grid element.
+ */
+ struct CCGElem ***boundary_elements;
+} SubdivCCGAdjacentEdge;
+
+/* Definition of a vertex which is adjacent to at least one of the faces. */
+typedef struct SubdivCCGAdjacentVertex {
+ int num_adjacent_faces;
+ /* Indexed by adjacent face index. */
+ SubdivCCGFace **faces;
+ /* Indexed by adjacent face index, points to a grid element.
+ */
+ struct CCGElem **corner_elements;
+} SubdivCCGAdjacentVertex;
+
+/* Representation of subdivision surface which uses CCG grids. */
+typedef struct SubdivCCG {
+ /* This is a subdivision surface this CCG was created for.
+ *
+ * TODO(sergey): Make sure the whole descriptor is valid, including all the
+ * displacement attached to the surface.
+ */
+ struct Subdiv *subdiv;
+ /* A level at which geometry was subdivided. This is what defines grid
+ * resolution. It is NOT the topology refinement level.
+ */
+ int level;
+ /* Resolution of grid. All grids have matching resolution, and resolution
+ * is same as ptex created for non-quad polygons.
+ */
+ int grid_size;
+ /* Grids represent limit surface, with displacement applied. Grids are
+ * corresponding to face-corners of coarse mesh, each grid has
+ * grid_size^2 elements.
+ */
+ /* Indexed by a grid index, points to a grid data which is stored in
+ * grids_storage.
+ */
+ struct CCGElem **grids;
+ /* Flat array of all grids' data. */
+ unsigned char *grids_storage;
+ int num_grids;
+ /* Loose edges, each array element contains grid_size elements
+ * corresponding to vertices created by subdividing coarse edges.
+ */
+ struct CCGElem **edges;
+ int num_edges;
+ /* Loose vertices. Every element corresponds to a loose vertex from a coarse
+ * mesh, every coarse loose vertex corresponds to a single sundivided
+ * element.
+ */
+ struct CCGElem *vertices;
+ int num_vertices;
+ /* Denotes which layers present in the elements.
+ *
+ * Grids always has coordinates, followed by extra layers which are set to
+ * truth here.
+ */
+ bool has_normal;
+ bool has_mask;
+ /* Offsets of corresponding data layers in the elements. */
+ int normal_offset;
+ int mask_offset;
+
+ /* Faces from which grids are emitted. */
+ int num_faces;
+ SubdivCCGFace *faces;
+ /* Indexed by grid index, points to corresponding face from `faces`. */
+ SubdivCCGFace **grid_faces;
+
+ /* Edges which are adjacent to faces.
+ * Used for faster grid stitching, in the cost of extra memory.
+ */
+ int num_adjacent_edges;
+ SubdivCCGAdjacentEdge *adjacent_edges;
+
+ /* Vertices which are adjacent to faces
+ * Used for faster grid stitching, in the cost of extra memory.
+ */
+ int num_adjacent_vertices;
+ SubdivCCGAdjacentVertex *adjacent_vertices;
+
+ struct DMFlagMat *grid_flag_mats;
+ BLI_bitmap **grid_hidden;
+
+ /* TODO(sergey): Consider adding some accessors to a "decoded" geometry,
+ * to make integration with draw manager and such easy.
+ */
+
+ /* TODO(sergey): Consider adding CD layers here, so we can draw final mesh
+ * from grids, and have UVs and such work.
+ */
+
+ /* Integration with sculpting. */
+ /* TODO(sergey): Is this really best way to go? Kind of annoying to have
+ * such use-related flags in a more or less generic structure.
+ */
+ struct {
+ /* Corresponds to MULTIRES_COORDS_MODIFIED. */
+ bool coords;
+ /* Corresponds to MULTIRES_HIDDEN_MODIFIED. */
+ bool hidden;
+ } dirty;
+} SubdivCCG;
+
+/* Create real hi-res CCG from subdivision.
+ *
+ * NOTE: Subdiv is expected to be refined and ready for evaluation.
+ * NOTE: CCG becomes an owner of subdiv.
+ *
+ * TODO(sergey): Allow some user-counter or more explicit control over who owns
+ * the Subdiv. The goal should be to allow viewport GL Mesh and CCG to share
+ * same Subsurf without conflicts.
+ */
+struct SubdivCCG *BKE_subdiv_to_ccg(
+ struct Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ SubdivCCGMask *mask_evaluator);
+
+/* Destroy CCG representation of subdivision surface. */
+void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg);
+
+/* Helper function, creates Mesh structure which is properly setup to use
+ * grids.
+ */
+struct Mesh *BKE_subdiv_to_ccg_mesh(
+ struct Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ const struct Mesh *coarse_mesh);
+
+/* Create a key for accessing grid elements at a given level. */
+void BKE_subdiv_ccg_key(
+ struct CCGKey *key, const SubdivCCG *subdiv_ccg, int level);
+void BKE_subdiv_ccg_key_top_level(
+ struct CCGKey *key, const SubdivCCG *subdiv_ccg);
+
+/* Recalculate all normals based on grid element coordinates. */
+void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg);
+
+/* Average grid coordinates and normals along the grid boundatries. */
+void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg);
+
+/* Similar to above, but only updates given faces. */
+void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG *subdiv_ccg,
+ struct CCGFace **effected_faces,
+ int num_effected_faces);
+
+#endif /* __BKE_SUBDIV_CCG_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
new file mode 100644
index 00000000000..0ea5c978e62
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -0,0 +1,127 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv_eval.h
+ * \ingroup bke
+ * \since September 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_EVAL_H__
+#define __BKE_SUBDIV_EVAL_H__
+
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct Subdiv;
+
+/* Returns true if evaluator is ready for use. */
+bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
+bool BKE_subdiv_eval_update_from_mesh(struct Subdiv *subdiv,
+ const struct Mesh *mesh);
+
+/* Single point queries. */
+
+void BKE_subdiv_eval_limit_point(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3]);
+void BKE_subdiv_eval_limit_point_and_derivatives(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], float r_dPdu[3], float r_dPdv[3]);
+void BKE_subdiv_eval_limit_point_and_normal(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], float r_N[3]);
+void BKE_subdiv_eval_limit_point_and_short_normal(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], short r_N[3]);
+
+void BKE_subdiv_eval_face_varying(
+ struct Subdiv *subdiv,
+ const int face_varying_channel,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_varying[2]);
+
+/* NOTE: Expects derivatives to be correct.
+ *
+ * TODO(sergey): This is currently used together with
+ * BKE_subdiv_eval_final_point() which cas easily evaluate derivatives.
+ * Would be nice to have dispalcement evaluation function which does not require
+ * knowing derivatives ahead of a time.
+ */
+void BKE_subdiv_eval_displacement(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3]);
+
+void BKE_subdiv_eval_final_point(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3]);
+
+/* Patch queries at given resolution.
+ *
+ * Will evaluate patch at uniformly distributed (u, v) coordinates on a grid
+ * of given resolution, producing resolution^2 evaluation points. The order
+ * goes as u in rows, v in columns.
+ */
+
+void BKE_subdiv_eval_limit_patch_resolution_point(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *buffer, const int offset, const int stride);
+void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *du_buffer, const int du_offset, const int du_stride,
+ void *dv_buffer, const int dv_offset, const int dv_stride);
+void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride);
+void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(
+ struct Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride);
+
+#endif /* __BKE_SUBDIV_EVAL_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_foreach.h b/source/blender/blenkernel/BKE_subdiv_foreach.h
new file mode 100644
index 00000000000..d4ef0ee3601
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_foreach.h
@@ -0,0 +1,181 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv_foreach.h
+ * \ingroup bke
+ * \since September 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_FOREACH_H__
+#define __BKE_SUBDIV_FOREACH_H__
+
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct Subdiv;
+struct SubdivForeachContext;
+struct SubdivToMeshSettings;
+
+typedef bool (*SubdivForeachTopologyInformationCb)(
+ const struct SubdivForeachContext *context,
+ const int num_vertices,
+ const int num_edges,
+ const int num_loops,
+ const int num_polygons);
+
+typedef void (*SubdivForeachVertexFromCornerCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_vertex_index,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index);
+
+typedef void (*SubdivForeachVertexFromEdgeCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_edge_index,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index);
+
+typedef void (*SubdivForeachVertexInnerCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index);
+
+typedef void (*SubdivForeachEdgeCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int coarse_edge_index,
+ const int subdiv_edge_index,
+ const int subdiv_v1, const int subdiv_v2);
+
+typedef void (*SubdivForeachLoopCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_loop_index,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_loop_index,
+ const int subdiv_vertex_index, const int subdiv_edge_index);
+
+typedef void (*SubdivForeachPolygonCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int coarse_poly_index,
+ const int subdiv_poly_index,
+ const int start_loop_index, const int num_loops);
+
+typedef void (*SubdivForeachLooseCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int coarse_vertex_index,
+ const int subdiv_vertex_index);
+
+typedef void (*SubdivForeachVertexOfLooseEdgeCb)(
+ const struct SubdivForeachContext *context,
+ void *tls,
+ const int coarse_edge_index,
+ const float u,
+ const int subdiv_vertex_index);
+
+typedef struct SubdivForeachContext {
+ /* Is called when topology information becomes available.
+ * Is only called once.
+ *
+ * NOTE: If this callback returns false, the foreach loop is aborted.
+ */
+ SubdivForeachTopologyInformationCb topology_info;
+ /* These callbacks are called from every ptex which shares "emitting"
+ * vertex or edge.
+ */
+ SubdivForeachVertexFromCornerCb vertex_every_corner;
+ SubdivForeachVertexFromEdgeCb vertex_every_edge;
+ /* Those callbacks are run once per subdivision vertex, ptex is undefined
+ * as in it will be whatever first ptex face happened to be tarversed in
+ * the multi-threaded environment ahd which shares "emitting" vertex or
+ * edge.
+ */
+ SubdivForeachVertexFromCornerCb vertex_corner;
+ SubdivForeachVertexFromEdgeCb vertex_edge;
+ /* Called exactly once, always corresponds to a single ptex face. */
+ SubdivForeachVertexInnerCb vertex_inner;
+ /* Called once for each loose vertex. One loose coarse vertexcorresponds
+ * to a single subdivision vertex.
+ */
+ SubdivForeachLooseCb vertex_loose;
+ /* Called once per vertex created for loose edge. */
+ SubdivForeachVertexOfLooseEdgeCb vertex_of_loose_edge;
+ /* NOTE: If subdivided edge does not come from coarse edge, ORIGINDEX_NONE
+ * will be passed as coarse_edge_index.
+ */
+ SubdivForeachEdgeCb edge;
+ /* NOTE: If subdivided loop does not come from coarse loop, ORIGINDEX_NONE
+ * will be passed as coarse_loop_index.
+ */
+ SubdivForeachLoopCb loop;
+ SubdivForeachPolygonCb poly;
+
+ /* User-defined pointer, to allow callbacks know something about context the
+ * traversal is happening for,
+ */
+ void *user_data;
+
+ /* Initial value of TLS data. */
+ void *user_data_tls;
+ /* Size of TLS data. */
+ size_t user_data_tls_size;
+ /* Function to free TLS storage. */
+ void (*user_data_tls_free)(void *tls);
+} SubdivForeachContext;
+
+/* Invokes callbacks in the order and with values which corresponds to creation
+ * of final subdivided mesh.
+ *
+ * Returns truth if the whole topology was traversed, without any early exits.
+ *
+ * TODO(sergey): Need to either get rid of subdiv or of coarse_mesh.
+ * The main point here is th be abel to get base level topology, which can be
+ * done with either of those. Having both of them is kind of redundant.
+ */
+bool BKE_subdiv_foreach_subdiv_geometry(
+ struct Subdiv *subdiv,
+ const struct SubdivForeachContext *context,
+ const struct SubdivToMeshSettings *mesh_settings,
+ const struct Mesh *coarse_mesh);
+
+#endif /* __BKE_SUBDIV_FOREACH_H__ */
diff --git a/source/blender/blenkernel/BKE_subdiv_mesh.h b/source/blender/blenkernel/BKE_subdiv_mesh.h
new file mode 100644
index 00000000000..f719527eed8
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_mesh.h
@@ -0,0 +1,56 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_subdiv_mesh.h
+ * \ingroup bke
+ * \since September 2018
+ * \author Sergey Sharybin
+ */
+
+#ifndef __BKE_SUBDIV_MESH_H__
+#define __BKE_SUBDIV_MESH_H__
+
+#include "BLI_sys_types.h"
+
+struct Mesh;
+struct Subdiv;
+
+typedef struct SubdivToMeshSettings {
+ /* Resolution at which regular ptex (created for quad polygon) are being
+ * evaluated. This defines how many vertices final mesh will have: every
+ * regular ptex has resolution^2 vertices. Special (irregular, or ptex
+ * created for a corner of non-quad polygon) will have resolution of
+ * `resolution - 1`.
+ */
+ int resolution;
+} SubdivToMeshSettings;
+
+/* Create real hi-res mesh from subdivision, all geometry is "real". */
+struct Mesh *BKE_subdiv_to_mesh(
+ struct Subdiv *subdiv,
+ const SubdivToMeshSettings *settings,
+ const struct Mesh *coarse_mesh);
+
+#endif /* __BKE_SUBDIV)MESH_H__ */
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 96320415b16..6cb09ff8822 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -67,6 +67,7 @@ typedef enum {
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
+ struct Scene *scene,
float (*vertCos)[3],
SubsurfFlags flags);
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index b53af3cec53..e7a8fb1c4a9 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -112,10 +112,6 @@ bool txt_cursor_is_line_end(struct Text *text);
int txt_calc_tab_left(struct TextLine *line, int ch);
int txt_calc_tab_right(struct TextLine *line, int ch);
-#if 0
-void txt_print_undo (struct Text *text);
-#endif
-
/* utility functions, could be moved somewhere more generic but are python/text related */
int text_check_bracket(const char ch);
bool text_check_delim(const char ch);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 7ffa22ac49b..228e17cd2ef 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -40,7 +40,6 @@ extern "C" {
struct bNode;
struct Brush;
struct ColorBand;
-struct EnvMap;
struct FreestyleLineStyle;
struct ImagePool;
struct Lamp;
@@ -53,7 +52,6 @@ struct PointDensity;
struct Tex;
struct TexMapping;
struct TexResult;
-struct VoxelData;
struct World;
/* in ColorBand struct */
@@ -76,27 +74,17 @@ struct MTex *BKE_texture_mtex_add_id(struct ID *id, int slot);
// void autotexname(struct Tex *tex);
struct Tex *give_current_object_texture(struct Object *ob);
-struct Tex *give_current_material_texture(struct Material *ma);
-struct Tex *give_current_lamp_texture(struct Lamp *la);
struct Tex *give_current_linestyle_texture(struct FreestyleLineStyle *linestyle);
-struct Tex *give_current_world_texture(struct World *world);
struct Tex *give_current_brush_texture(struct Brush *br);
struct Tex *give_current_particle_texture(struct ParticleSettings *part);
-struct bNode *give_current_material_texture_node(struct Material *ma);
-
bool give_active_mtex(struct ID *id, struct MTex ***mtex_ar, short *act);
void set_active_mtex(struct ID *id, short act);
void set_current_brush_texture(struct Brush *br, struct Tex *tex);
-void set_current_world_texture(struct World *wo, struct Tex *tex);
-void set_current_material_texture(struct Material *ma, struct Tex *tex);
-void set_current_lamp_texture(struct Lamp *la, struct Tex *tex);
void set_current_linestyle_texture(struct FreestyleLineStyle *linestyle, struct Tex *tex);
void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex);
-bool has_current_material_texture(struct Material *ma);
-
struct TexMapping *BKE_texture_mapping_add(int type);
void BKE_texture_mapping_default(struct TexMapping *texmap, int type);
void BKE_texture_mapping_init(struct TexMapping *texmap);
@@ -104,26 +92,12 @@ void BKE_texture_mapping_init(struct TexMapping *texmap);
struct ColorMapping *BKE_texture_colormapping_add(void);
void BKE_texture_colormapping_default(struct ColorMapping *colormap);
-void BKE_texture_envmap_free_data(struct EnvMap *env);
-void BKE_texture_envmap_free(struct EnvMap *env);
-struct EnvMap *BKE_texture_envmap_add(void);
-struct EnvMap *BKE_texture_envmap_copy(const struct EnvMap *env, const int flag);
-
void BKE_texture_pointdensity_init_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free_data(struct PointDensity *pd);
void BKE_texture_pointdensity_free(struct PointDensity *pd);
struct PointDensity *BKE_texture_pointdensity_add(void);
struct PointDensity *BKE_texture_pointdensity_copy(const struct PointDensity *pd, const int flag);
-void BKE_texture_voxeldata_free_data(struct VoxelData *vd);
-void BKE_texture_voxeldata_free(struct VoxelData *vd);
-struct VoxelData *BKE_texture_voxeldata_add(void);
-struct VoxelData *BKE_texture_voxeldata_copy(struct VoxelData *vd);
-
-void BKE_texture_ocean_free(struct OceanTex *ot);
-struct OceanTex *BKE_texture_ocean_add(void);
-struct OceanTex *BKE_texture_ocean_copy(const struct OceanTex *ot, const int flag);
-
bool BKE_texture_dependsOnTime(const struct Tex *texture);
bool BKE_texture_is_image_user(const struct Tex *tex);
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 13302caa09d..0c3b118d947 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -32,6 +32,7 @@
* \author Sergey Sharybin
*/
+struct Depsgraph;
struct bGPDlayer;
struct ImBuf;
struct ListBase;
@@ -61,7 +62,8 @@ struct ListBase *BKE_tracking_get_active_plane_tracks(struct MovieTracking *trac
struct MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(struct MovieTracking *tracking);
/* matrices for constraints and drawing */
-void BKE_tracking_get_camera_object_matrix(struct Scene *scene, struct Object *ob, float mat[4][4]);
+void BKE_tracking_get_camera_object_matrix(
+ struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, float mat[4][4]);
void BKE_tracking_get_projection_matrix(struct MovieTracking *tracking, struct MovieTrackingObject *object,
int framenr, int winx, int winy, float mat[4][4]);
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index 82a4659eec7..bb7fb006038 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -31,14 +31,23 @@
extern "C" {
#endif
+struct UnitSettings;
+
/* in all cases the value is assumed to be scaled by the user preference */
/* humanly readable representation of a value in units (used for button drawing) */
-size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
+size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
+size_t bUnit_AsString2(char *str, int len_max, double value, int prec, int type, const struct UnitSettings *settings, bool pad);
/* replace units with values, used before python button evaluation */
bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type);
+/* return true if the string contains any valid unit for the given type */
+bool bUnit_ContainsUnit(const char *str, int system, int type);
+
+/* if user does not specify a unit, multiply with this value */
+double bUnit_PreferredUnitScalar(const struct UnitSettings *settings, int type);
+
/* make string keyboard-friendly: 10µm --> 10um */
void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type);
@@ -56,9 +65,11 @@ bool bUnit_IsValid(int system, int type);
void bUnit_GetSystem(int system, int type, void const **r_usys_pt, int *r_len);
int bUnit_GetBaseUnit(const void *usys_pt);
+int bUnit_GetBaseUnitOfType(int system, int type);
const char *bUnit_GetName(const void *usys_pt, int index);
const char *bUnit_GetNameDisplay(const void *usys_pt, int index);
double bUnit_GetScaler(const void *usys_pt, int index);
+bool bUnit_IsSuppressed(const void *usys_pt, int index);
/* aligned with PropertyUnit */
enum {
diff --git a/source/blender/blenkernel/BKE_workspace.h b/source/blender/blenkernel/BKE_workspace.h
new file mode 100644
index 00000000000..6902fb631e4
--- /dev/null
+++ b/source/blender/blenkernel/BKE_workspace.h
@@ -0,0 +1,110 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file BKE_workspace.h
+ * \ingroup bke
+ */
+
+#ifndef __BKE_WORKSPACE_H__
+#define __BKE_WORKSPACE_H__
+
+#include "BLI_compiler_attrs.h"
+
+struct bScreen;
+struct bToolRef;
+struct Main;
+struct Scene;
+struct TransformOrientation;
+struct ViewLayer;
+
+/* -------------------------------------------------------------------- */
+/* Create, delete, init */
+
+struct WorkSpace *BKE_workspace_add(struct Main *bmain, const char *name);
+void BKE_workspace_free(struct WorkSpace *workspace);
+void BKE_workspace_remove(struct Main *bmain, struct WorkSpace *workspace);
+
+struct WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const struct Main *bmain);
+void BKE_workspace_instance_hook_free(const struct Main *bmain, struct WorkSpaceInstanceHook *hook);
+
+struct WorkSpaceLayout *BKE_workspace_layout_add(
+ struct Main *bmain,
+ struct WorkSpace *workspace,
+ struct bScreen *screen,
+ const char *name) ATTR_NONNULL();
+void BKE_workspace_layout_remove(
+ struct Main *bmain,
+ struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL();
+
+void BKE_workspace_relations_free(
+ ListBase *relation_list);
+
+
+/* -------------------------------------------------------------------- */
+/* General Utils */
+
+struct WorkSpaceLayout *BKE_workspace_layout_find(
+ const struct WorkSpace *workspace, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+struct WorkSpaceLayout *BKE_workspace_layout_find_global(
+ const struct Main *bmain, const struct bScreen *screen,
+ struct WorkSpace **r_workspace) ATTR_NONNULL(1, 2);
+
+struct WorkSpaceLayout *BKE_workspace_layout_iter_circular(
+ const struct WorkSpace *workspace, struct WorkSpaceLayout *start,
+ bool (*callback)(const struct WorkSpaceLayout *layout, void *arg),
+ void *arg, const bool iter_backward);
+
+void BKE_workspace_tool_remove(
+ struct WorkSpace *workspace, struct bToolRef *tref) ATTR_NONNULL(1, 2);
+
+/* -------------------------------------------------------------------- */
+/* Getters/Setters */
+
+#define GETTER_ATTRS ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
+#define SETTER_ATTRS ATTR_NONNULL(1)
+
+struct WorkSpace *BKE_workspace_active_get(struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
+void BKE_workspace_active_set(struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace) SETTER_ATTRS;
+struct WorkSpaceLayout *BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
+void BKE_workspace_active_layout_set(struct WorkSpaceInstanceHook *hook, struct WorkSpaceLayout *layout) SETTER_ATTRS;
+struct bScreen *BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS;
+void BKE_workspace_active_screen_set(
+ struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct bScreen *screen) SETTER_ATTRS;
+
+struct ListBase *BKE_workspace_layouts_get(struct WorkSpace *workspace) GETTER_ATTRS;
+
+const char *BKE_workspace_layout_name_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
+void BKE_workspace_layout_name_set(
+ struct WorkSpace *workspace, struct WorkSpaceLayout *layout, const char *new_name) ATTR_NONNULL();
+struct bScreen *BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS;
+void BKE_workspace_layout_screen_set(struct WorkSpaceLayout *layout, struct bScreen *screen) SETTER_ATTRS;
+
+struct WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
+ const struct WorkSpaceInstanceHook *hook, const struct WorkSpace *workspace) GETTER_ATTRS;
+void BKE_workspace_hook_layout_for_workspace_set(
+ struct WorkSpaceInstanceHook *hook, struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL();
+
+bool BKE_workspace_owner_id_check(
+ const struct WorkSpace *workspace, const char *owner_id) ATTR_NONNULL();
+
+#undef GETTER_ATTRS
+#undef SETTER_ATTRS
+
+#endif /* __BKE_WORKSPACE_H__ */
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index b28bac08727..eb0548c682e 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -33,6 +33,7 @@
* \author nzc
*/
+struct Depsgraph;
struct Main;
struct World;
@@ -43,5 +44,6 @@ void BKE_world_copy_data(struct Main *bmain, struct World *wrld_dst, const struc
struct World *BKE_world_copy(struct Main *bmain, const struct World *wrld);
struct World *BKE_world_localize(struct World *wrld);
void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local);
+void BKE_world_eval(struct Depsgraph *depsgraph, struct World *world);
-#endif /* __BKE_WORLD_H__ */
+#endif
diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h
deleted file mode 100644
index c38b1b196c3..00000000000
--- a/source/blender/blenkernel/BKE_writeframeserver.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BKE_WRITEFRAMESERVER_H__
-#define __BKE_WRITEFRAMESERVER_H__
-
-/** \file BKE_writeframeserver.h
- * \ingroup bke
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct RenderData;
-struct ReportList;
-struct Scene;
-
-int BKE_frameserver_start(
- void *context_v, struct Scene *scene, struct RenderData *rd, int rectx, int recty,
- struct ReportList *reports, bool preview, const char *suffix);
-void BKE_frameserver_end(void *context_v);
-int BKE_frameserver_append(
- void *context_v, struct RenderData *rd, int start_frame, int frame, int *pixels,
- int rectx, int recty, const char *suffix, struct ReportList *reports);
-int BKE_frameserver_loop(void *context_v, struct RenderData *rd, struct ReportList *reports);
-void *BKE_frameserver_context_create(void);
-void BKE_frameserver_context_free(void *context_v);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 45f2ac083dd..4161a5ecd79 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../blenloader
../blentranslation
../depsgraph
+ ../draw
../gpu
../ikplugin
../imbuf
@@ -37,6 +38,8 @@ set(INC
../makesrna
../bmesh
../modifiers
+ ../gpencil_modifiers
+ ../shader_fx
../nodes
../physics
../render/extern/include
@@ -50,6 +53,7 @@ set(INC
../../../intern/atomic
../../../intern/clog
../../../intern/libmv
+ ../../../intern/opensubdiv
../../../extern/curve_fit_nd
)
@@ -76,17 +80,17 @@ set(SRC
intern/blender.c
intern/blender_copybuffer.c
intern/blender_undo.c
+ intern/blender_user_menu.c
intern/blendfile.c
- intern/bmfont.c
intern/boids.c
intern/bpath.c
intern/brush.c
- intern/bullet.c
intern/bvhutils.c
intern/cachefile.c
intern/camera.c
intern/cdderivedmesh.c
intern/cloth.c
+ intern/collection.c
intern/collision.c
intern/colorband.c
intern/colortools.c
@@ -99,13 +103,14 @@ set(SRC
intern/customdata_file.c
intern/data_transfer.c
intern/deform.c
- intern/depsgraph.c
intern/displist.c
intern/dynamicpaint.c
intern/editderivedmesh.c
intern/editlattice.c
intern/editmesh.c
intern/editmesh_bvh.c
+ intern/editmesh_cache.c
+ intern/editmesh_tangent.c
intern/effect.c
intern/fcurve.c
intern/fluidsim.c
@@ -113,8 +118,9 @@ set(SRC
intern/font.c
intern/freestyle.c
intern/gpencil.c
- intern/group.c
+ intern/gpencil_modifier.c
intern/icons.c
+ intern/icons_rasterize.c
intern/idcode.c
intern/idprop.c
intern/idprop_utils.c
@@ -126,9 +132,11 @@ set(SRC
intern/lattice.c
intern/library.c
intern/library_idmap.c
+ intern/library_override.c
intern/library_query.c
intern/library_remap.c
intern/linestyle.c
+ intern/main.c
intern/mask.c
intern/mask_evaluate.c
intern/mask_rasterize.c
@@ -138,16 +146,22 @@ set(SRC
intern/mesh.c
intern/mesh_convert.c
intern/mesh_evaluate.c
+ intern/mesh_iterators.c
intern/mesh_mapping.c
+ intern/mesh_merge.c
intern/mesh_remap.c
+ intern/mesh_runtime.c
+ intern/mesh_tangent.c
intern/mesh_validate.c
intern/modifier.c
- intern/modifiers_bmesh.c
intern/movieclip.c
intern/multires.c
+ intern/multires_reshape.c
+ intern/multires_subdiv.c
intern/nla.c
intern/node.c
intern/object.c
+ intern/object_facemap.c
intern/object_deform.c
intern/object_dupli.c
intern/object_update.c
@@ -155,6 +169,7 @@ set(SRC
intern/outliner_treehash.c
intern/packedFile.c
intern/paint.c
+ intern/paint_toolslots.c
intern/particle.c
intern/particle_child.c
intern/particle_distribute.c
@@ -162,22 +177,35 @@ set(SRC
intern/pbvh.c
intern/pbvh_bmesh.c
intern/pointcache.c
- intern/property.c
+ intern/layer.c
+ intern/layer_utils.c
+ intern/lightprobe.c
intern/report.c
intern/rigidbody.c
- intern/sca.c
intern/scene.c
intern/screen.c
intern/seqcache.c
intern/seqeffects.c
intern/seqmodifier.c
intern/sequencer.c
+ intern/shader_fx.c
intern/shrinkwrap.c
- intern/sketch.c
intern/smoke.c
intern/softbody.c
intern/sound.c
intern/speaker.c
+ intern/studiolight.c
+ intern/subdiv.c
+ intern/subdiv_ccg.c
+ intern/subdiv_ccg_mask.c
+ intern/subdiv_converter.c
+ intern/subdiv_converter_mesh.c
+ intern/subdiv_displacement.c
+ intern/subdiv_displacement_multires.c
+ intern/subdiv_eval.c
+ intern/subdiv_foreach.c
+ intern/subdiv_mesh.c
+ intern/subdiv_stats.c
intern/subsurf_ccg.c
intern/suggestions.c
intern/text.c
@@ -192,9 +220,9 @@ set(SRC
intern/tracking_util.c
intern/undo_system.c
intern/unit.c
+ intern/workspace.c
intern/world.c
intern/writeavi.c
- intern/writeframeserver.c
BKE_DerivedMesh.h
BKE_action.h
@@ -207,20 +235,19 @@ set(SRC
BKE_blender.h
BKE_blender_copybuffer.h
BKE_blender_undo.h
+ BKE_blender_user_menu.h
BKE_blender_version.h
BKE_blendfile.h
- BKE_bmfont.h
- BKE_bmfont_types.h
BKE_boids.h
BKE_bpath.h
BKE_brush.h
- BKE_bullet.h
BKE_bvhutils.h
BKE_cachefile.h
BKE_camera.h
BKE_ccg.h
BKE_cdderivedmesh.h
BKE_cloth.h
+ BKE_collection.h
BKE_collision.h
BKE_colorband.h
BKE_colortools.h
@@ -232,12 +259,13 @@ set(SRC
BKE_customdata_file.h
BKE_data_transfer.h
BKE_deform.h
- BKE_depsgraph.h
BKE_displist.h
BKE_dynamicpaint.h
BKE_editlattice.h
BKE_editmesh.h
BKE_editmesh_bvh.h
+ BKE_editmesh_cache.h
+ BKE_editmesh_tangent.h
BKE_effect.h
BKE_fcurve.h
BKE_fluidsim.h
@@ -245,7 +273,7 @@ set(SRC
BKE_freestyle.h
BKE_global.h
BKE_gpencil.h
- BKE_group.h
+ BKE_gpencil_modifier.h
BKE_icons.h
BKE_idcode.h
BKE_idprop.h
@@ -256,6 +284,7 @@ set(SRC
BKE_lattice.h
BKE_library.h
BKE_library_idmap.h
+ BKE_library_override.h
BKE_library_query.h
BKE_library_remap.h
BKE_linestyle.h
@@ -265,14 +294,18 @@ set(SRC
BKE_mball.h
BKE_mball_tessellate.h
BKE_mesh.h
+ BKE_mesh_iterators.h
BKE_mesh_mapping.h
BKE_mesh_remap.h
+ BKE_mesh_runtime.h
+ BKE_mesh_tangent.h
BKE_modifier.h
BKE_movieclip.h
BKE_multires.h
BKE_nla.h
BKE_node.h
BKE_object.h
+ BKE_object_facemap.h
BKE_object_deform.h
BKE_ocean.h
BKE_outliner_treehash.h
@@ -281,19 +314,25 @@ set(SRC
BKE_particle.h
BKE_pbvh.h
BKE_pointcache.h
- BKE_property.h
+ BKE_layer.h
+ BKE_lightprobe.h
BKE_report.h
BKE_rigidbody.h
- BKE_sca.h
BKE_scene.h
BKE_screen.h
BKE_sequencer.h
+ BKE_shader_fx.h
BKE_shrinkwrap.h
- BKE_sketch.h
BKE_smoke.h
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
+ BKE_studiolight.h
+ BKE_subdiv.h
+ BKE_subdiv_ccg.h
+ BKE_subdiv_eval.h
+ BKE_subdiv_foreach.h
+ BKE_subdiv_mesh.h
BKE_subsurf.h
BKE_suggestions.h
BKE_text.h
@@ -301,19 +340,19 @@ set(SRC
BKE_tracking.h
BKE_undo_system.h
BKE_unit.h
+ BKE_workspace.h
BKE_world.h
BKE_writeavi.h
- BKE_writeframeserver.h
- depsgraph_private.h
nla_private.h
tracking_private.h
particle_private.h
intern/CCGSubSurf.h
intern/CCGSubSurf_inline.h
intern/CCGSubSurf_intern.h
- intern/pbvh_intern.h
intern/data_transfer_intern.h
+ intern/pbvh_intern.h
+ intern/subdiv_converter.h
)
if(WITH_BINRELOC)
@@ -332,7 +371,7 @@ if(WIN32)
endif()
if(WITH_AUDASPACE)
- add_definitions(${AUDASPACE_DEFINITIONS})
+ add_definitions(-DWITH_AUDASPACE)
list(APPEND INC_SYS
${AUDASPACE_C_INCLUDE_DIRS}
@@ -420,6 +459,10 @@ if(WITH_PYTHON)
)
add_definitions(-DWITH_PYTHON)
+ if(WITH_PYTHON_SAFETY)
+ add_definitions(-DWITH_PYTHON_SAFETY)
+ endif()
+
if(WITH_PYTHON_SECURITY)
add_definitions(-DWITH_PYTHON_SECURITY)
endif()
@@ -472,18 +515,6 @@ if(WITH_LZMA)
add_definitions(-DWITH_LZMA)
endif()
-if(WITH_GAMEENGINE)
- list(APPEND INC_SYS
- ../../../extern/recastnavigation
- )
- list(APPEND SRC
- intern/navmesh_conversion.c
- BKE_navmesh_conversion.h
- )
-
- add_definitions(-DWITH_GAMEENGINE)
-endif()
-
if(WITH_LIBMV)
add_definitions(-DWITH_LIBMV)
endif()
@@ -513,9 +544,11 @@ endif()
if(WITH_OPENSUBDIV)
add_definitions(-DWITH_OPENSUBDIV)
list(APPEND INC_SYS
- ../../../intern/opensubdiv
${OPENSUBDIV_INCLUDE_DIRS}
)
+ if(WITH_OPENSUBDIV_MODIFIER)
+ add_definitions(-DWITH_OPENSUBDIV_MODIFIER)
+ endif()
endif()
if(WITH_OPENVDB)
@@ -536,8 +569,4 @@ endif()
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
#endif()
-if(WITH_LEGACY_DEPSGRAPH)
- add_definitions(-DWITH_LEGACY_DEPSGRAPH)
-endif()
-
blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h
deleted file mode 100644
index 69ca75836d9..00000000000
--- a/source/blender/blenkernel/depsgraph_private.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/depsgraph_private.h
- * \ingroup bke
- */
-
-#ifndef __DEPSGRAPH_PRIVATE_H__
-#define __DEPSGRAPH_PRIVATE_H__
-
-#include "BKE_depsgraph.h"
-#include "DNA_constraint_types.h"
-#include "BKE_constraint.h"
-
-struct Scene;
-struct Group;
-struct EffectorWeights;
-struct ModifierData;
-
-/* **** DAG relation types *** */
-
-/* scene link to object */
-#define DAG_RL_SCENE (1 << 0)
-/* object link to data */
-#define DAG_RL_DATA (1 << 1)
-
-/* object changes object (parent, track, constraints) */
-#define DAG_RL_OB_OB (1 << 2)
-/* object changes obdata (hooks, constraints) */
-#define DAG_RL_OB_DATA (1 << 3)
-/* data changes object (vertex parent) */
-#define DAG_RL_DATA_OB (1 << 4)
-/* data changes data (deformers) */
-#define DAG_RL_DATA_DATA (1 << 5)
-
-#define DAG_NO_RELATION (1 << 6)
-
-#define DAG_RL_ALL_BUT_DATA (DAG_RL_SCENE | DAG_RL_OB_OB | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_DATA_DATA)
-#define DAG_RL_ALL (DAG_RL_ALL_BUT_DATA | DAG_RL_DATA)
-
-
-#define DAGQUEUEALLOC 50
-
-enum {
- DAG_WHITE = 0,
- DAG_GRAY = 1,
- DAG_BLACK = 2
-};
-
-typedef struct DagAdjList {
- struct DagNode *node;
- short type;
- int count; /* number of identical arcs */
- unsigned int lay; // for flushing redraw/rebuild events
- const char *name;
- struct DagAdjList *next;
-} DagAdjList;
-
-
-typedef struct DagNode {
- int color;
- short type;
- float x, y, k;
- void *ob;
- void *first_ancestor;
- int ancestor_count;
- unsigned int lay; /* accumulated layers of its relations + itself */
- unsigned int scelay; /* layers due to being in scene */
- uint64_t customdata_mask; /* customdata mask */
- int lasttime; /* if lasttime != DagForest->time, this node was not evaluated yet for flushing */
- int BFS_dist; /* BFS distance */
- int DFS_dist; /* DFS distance */
- int DFS_dvtm; /* DFS discovery time */
- int DFS_fntm; /* DFS Finishing time */
- struct DagAdjList *child;
- struct DagAdjList *parent;
- struct DagNode *next;
-
- /* Threaded evaluation routines */
- uint32_t num_pending_parents; /* number of parents which are not updated yet
- * this node has got.
- * Used by threaded update for faster detect whether node could be
- * updated aready.
- */
- bool scheduled;
-
- /* Runtime flags mainly used to determine which extra data is to be evaluated
- * during object_handle_update(). Such an extra data is what depends on the
- * DAG topology, meaning this flags indicates the data evaluation of which
- * depends on the node dependencies.
- */
- short eval_flags;
-} DagNode;
-
-typedef struct DagNodeQueueElem {
- struct DagNode *node;
- struct DagNodeQueueElem *next;
-} DagNodeQueueElem;
-
-typedef struct DagNodeQueue {
- DagNodeQueueElem *first;
- DagNodeQueueElem *last;
- int count;
- int maxlevel;
- struct DagNodeQueue *freenodes;
-} DagNodeQueue;
-
-/* forest as we may have more than one DAG unconnected */
-typedef struct DagForest {
- ListBase DagNode;
- struct GHash *nodeHash;
- int numNodes;
- bool is_acyclic;
- int time; /* for flushing/tagging, compare with node->lasttime */
- bool ugly_hack_sorry; /* prevent type check */
- bool need_update;
-} DagForest;
-
-// queue operations
-DagNodeQueue *queue_create(int slots);
-void queue_raz(DagNodeQueue *queue);
-void push_queue(DagNodeQueue *queue, DagNode *node);
-void push_stack(DagNodeQueue *queue, DagNode *node);
-DagNode *pop_queue(DagNodeQueue *queue);
-DagNode *get_top_node_queue(DagNodeQueue *queue);
-void queue_delete(DagNodeQueue *queue);
-
-// Dag management
-DagForest *dag_init(void);
-DagForest *build_dag(struct Main *bmain, struct Scene *sce, short mask);
-void free_forest(struct DagForest *Dag);
-DagNode *dag_find_node(DagForest *forest, void *fob);
-DagNode *dag_add_node(DagForest *forest, void *fob);
-DagNode *dag_get_node(DagForest *forest, void *fob);
-DagNode *dag_get_sub_node(DagForest *forest, void *fob);
-void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel, const char *name);
-
-typedef bool (*DagCollobjFilterFunction)(struct Object *obj, struct ModifierData *md);
-
-void dag_add_collision_relations(DagForest *dag, struct Scene *scene, Object *ob, DagNode *node, struct Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name);
-void dag_add_forcefield_relations(DagForest *dag, struct Scene *scene, Object *ob, DagNode *node, struct EffectorWeights *eff, bool add_absorption, int skip_forcefield, const char *name);
-
-void graph_print_queue(DagNodeQueue *nqueue);
-void graph_print_queue_dist(DagNodeQueue *nqueue);
-void graph_print_adj_list(DagForest *dag);
-
-#endif /* __DEPSGRAPH_PRIVATE_H__ */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 40dea6ca663..6ec1b1b36b9 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -40,9 +40,11 @@
#ifdef WITH_OPENSUBDIV
# include "opensubdiv_capi.h"
# include "opensubdiv_converter_capi.h"
+# include "opensubdiv_evaluator_capi.h"
+# include "opensubdiv_topology_refiner_capi.h"
#endif
-#include "GL/glew.h"
+#include "GPU_glew.h"
/***/
@@ -329,7 +331,7 @@ void ccgSubSurf_free(CCGSubSurf *ss)
CCGAllocatorHDL allocator = ss->allocator;
#ifdef WITH_OPENSUBDIV
if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
+ openSubdiv_deleteEvaluator(ss->osd_evaluator);
}
if (ss->osd_mesh != NULL) {
ccgSubSurf__delete_osdGLMesh(ss->osd_mesh);
@@ -341,7 +343,7 @@ void ccgSubSurf_free(CCGSubSurf *ss)
MEM_freeN(ss->osd_coarse_coords);
}
if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner);
+ openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
}
#endif
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
index 50959d21425..e1cb82d7868 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -236,7 +236,7 @@ struct CCGSubSurf {
* Refiner is created from the modifier stack and used later from the main
* thread to construct GL mesh to avoid threaded access to GL.
*/
- struct OpenSubdiv_TopologyRefinerDescr *osd_topology_refiner; /* Only used at synchronization stage. */
+ struct OpenSubdiv_TopologyRefiner *osd_topology_refiner; /* Only used at synchronization stage. */
/* Denotes whether osd_mesh is invalid now due to topology changes and needs
* to be reconstructed.
*
@@ -249,7 +249,7 @@ struct CCGSubSurf {
/* ** CPU backend. ** */
/* Limit evaluator, used to evaluate CCG. */
- struct OpenSubdiv_EvaluatorDescr *osd_evaluator;
+ struct OpenSubdiv_Evaluator *osd_evaluator;
/* Next PTex face index, used while CCG synchronization
* to fill in PTex index of CCGFace.
*/
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 65c6518cee4..004a50205ba 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -42,8 +42,11 @@
#include "opensubdiv_capi.h"
#include "opensubdiv_converter_capi.h"
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_gl_mesh_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "GPU_extensions.h"
#define OSD_LOG if (false) printf
@@ -131,7 +134,6 @@ static bool compare_ccg_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
{
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
OpenSubdiv_Converter converter;
bool result;
if (ss->osd_mesh == NULL && ss->osd_topology_refiner == NULL) {
@@ -140,15 +142,10 @@ static bool compare_osd_derivedmesh_topology(CCGSubSurf *ss, DerivedMesh *dm)
/* TODO(sergey): De-duplicate with topology counter at the bottom of
* the file.
*/
- if (ss->osd_topology_refiner != NULL) {
- topology_refiner = ss->osd_topology_refiner;
- }
- else {
- topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- }
ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
- result = openSubdiv_topologyRefnerCompareConverter(topology_refiner,
- &converter);
+ result = openSubdiv_topologyRefinerCompareWithConverter(
+ ss->osd_topology_refiner,
+ &converter);
ccgSubSurf_converter_free(&converter);
return result;
}
@@ -159,22 +156,13 @@ static bool opensubdiv_is_topology_changed(CCGSubSurf *ss, DerivedMesh *dm)
return true;
}
if (ss->osd_topology_refiner != NULL) {
- int levels = openSubdiv_topologyRefinerGetSubdivLevel(
+ const int levels = ss->osd_topology_refiner->getSubdivisionLevel(
ss->osd_topology_refiner);
BLI_assert(ss->osd_mesh_invalid == true);
if (levels != ss->subdivLevels) {
return true;
}
}
- if (ss->osd_mesh != NULL && ss->osd_mesh_invalid == false) {
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner =
- openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- int levels = openSubdiv_topologyRefinerGetSubdivLevel(topology_refiner);
- BLI_assert(ss->osd_topology_refiner == NULL);
- if (levels != ss->subdivLevels) {
- return true;
- }
- }
if (ss->skip_grids == false) {
return compare_ccg_derivedmesh_topology(ss, dm) == false;
}
@@ -194,13 +182,13 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
/* Reset GPU part. */
ss->osd_mesh_invalid = true;
if (ss->osd_topology_refiner != NULL) {
- openSubdiv_deleteTopologyRefinerDescr(ss->osd_topology_refiner);
+ openSubdiv_deleteTopologyRefiner(ss->osd_topology_refiner);
ss->osd_topology_refiner = NULL;
}
- /* Reste CPU side. */
+ /* Reset CPU side. */
if (ss->osd_evaluator != NULL) {
- openSubdiv_deleteEvaluatorDescr(ss->osd_evaluator);
+ openSubdiv_deleteEvaluator(ss->osd_evaluator);
ss->osd_evaluator = NULL;
}
}
@@ -209,10 +197,10 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
{
BLI_assert(ss->meshIFC.numLayers == 3);
- openSubdiv_osdGLMeshUpdateVertexBuffer(ss->osd_mesh,
- (float *) ss->osd_coarse_coords,
- 0,
- ss->osd_num_coarse_coords);
+ ss->osd_mesh->setCoarsePositions(ss->osd_mesh,
+ (float *) ss->osd_coarse_coords,
+ 0,
+ ss->osd_num_coarse_coords);
}
bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
@@ -232,6 +220,9 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
CHECK_COMPUTE_TYPE(CUDA)
CHECK_COMPUTE_TYPE(GLSL_TRANSFORM_FEEDBACK)
CHECK_COMPUTE_TYPE(GLSL_COMPUTE)
+ default:
+ compute_type = OPENSUBDIV_EVALUATOR_CPU;
+ break;
#undef CHECK_COMPUTE_TYPE
}
@@ -256,9 +247,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(
ss->osd_topology_refiner,
- compute_type,
- ss->subdivLevels);
- ss->osd_topology_refiner = NULL;
+ compute_type);
if (UNLIKELY(ss->osd_mesh == NULL)) {
/* Most likely compute device is not available. */
@@ -266,13 +255,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
}
ccgSubSurf__updateGLMeshCoords(ss);
- openSubdiv_osdGLMeshRefine(ss->osd_mesh);
- openSubdiv_osdGLMeshSynchronize(ss->osd_mesh);
+ ss->osd_mesh->refine(ss->osd_mesh);
+ ss->osd_mesh->synchronize(ss->osd_mesh);
ss->osd_coarse_coords_invalid = false;
glBindVertexArray(ss->osd_vao);
- glBindBuffer(GL_ARRAY_BUFFER,
- openSubdiv_getOsdGLMeshVertexBuffer(ss->osd_mesh));
+ ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
@@ -286,12 +274,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
}
else if (ss->osd_coarse_coords_invalid) {
ccgSubSurf__updateGLMeshCoords(ss);
- openSubdiv_osdGLMeshRefine(ss->osd_mesh);
- openSubdiv_osdGLMeshSynchronize(ss->osd_mesh);
+ ss->osd_mesh->refine(ss->osd_mesh);
+ ss->osd_mesh->synchronize(ss->osd_mesh);
ss->osd_coarse_coords_invalid = false;
}
- openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, active_uv_index);
+ ss->osd_mesh->prepareDraw(ss->osd_mesh, use_osd_glsl, active_uv_index);
return true;
}
@@ -302,12 +290,12 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
if (LIKELY(ss->osd_mesh != NULL)) {
glBindVertexArray(ss->osd_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
- openSubdiv_getOsdGLMeshPatchIndexBuffer(ss->osd_mesh));
+ ss->osd_mesh->getPatchIndexBuffer(ss->osd_mesh));
- openSubdiv_osdGLMeshBindVertexBuffer(ss->osd_mesh);
+ ss->osd_mesh->bindVertexBuffer(ss->osd_mesh);
glBindVertexArray(ss->osd_vao);
- openSubdiv_osdGLMeshDisplay(ss->osd_mesh, fill_quads,
- start_partition, num_partitions);
+ ss->osd_mesh->drawPatches(ss->osd_mesh, fill_quads,
+ start_partition, num_partitions);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -316,33 +304,21 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss)
{
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
if (ss->osd_topology_refiner != NULL) {
- topology_refiner = ss->osd_topology_refiner;
- }
- else if (ss->osd_mesh != NULL) {
- topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- }
- else {
- return 0;
+ return ss->osd_topology_refiner->getNumFaces(
+ ss->osd_topology_refiner);
}
- return openSubdiv_topologyRefinerGetNumFaces(topology_refiner);
+ return 0;
}
/* Get number of vertices in base faces in a particular GL mesh. */
int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face)
{
- const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
if (ss->osd_topology_refiner != NULL) {
- topology_refiner = ss->osd_topology_refiner;
- }
- else if (ss->osd_mesh != NULL) {
- topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
- }
- else {
- return 0;
+ return ss->osd_topology_refiner->getNumFaceVertices(
+ ss->osd_topology_refiner, face);
}
- return openSubdiv_topologyRefinerGetNumFaceVerts(topology_refiner, face);
+ return 0;
}
void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids)
@@ -450,17 +426,21 @@ void ccgSubSurf_evaluatorFVarUV(CCGSubSurf *ss,
static bool opensubdiv_createEvaluator(CCGSubSurf *ss)
{
OpenSubdiv_Converter converter;
- OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+ OpenSubdiv_TopologyRefiner *topology_refiner;
if (ss->fMap->numEntries == 0) {
/* OpenSubdiv doesn't support meshes without faces. */
return false;
}
ccgSubSurf_converter_setup_from_ccg(ss, &converter);
- topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter);
+ OpenSubdiv_TopologyRefinerSettings settings;
+ settings.level = ss->subdivLevels;
+ settings.is_adaptive = false;
+ topology_refiner =
+ openSubdiv_createTopologyRefinerFromConverter(
+ &converter, &settings);
ccgSubSurf_converter_free(&converter);
ss->osd_evaluator =
- openSubdiv_createEvaluatorDescr(topology_refiner,
- ss->subdivLevels);
+ openSubdiv_createEvaluatorFromTopologyRefiner(topology_refiner);
if (ss->osd_evaluator == NULL) {
BLI_assert(!"OpenSubdiv initialization failed, should not happen.");
return false;
@@ -516,10 +496,11 @@ static void opensubdiv_updateEvaluatorCoarsePositions(CCGSubSurf *ss)
}
}
- openSubdiv_setEvaluatorCoarsePositions(ss->osd_evaluator,
- (float *)positions,
- 0,
- num_basis_verts);
+ ss->osd_evaluator->setCoarsePositions(ss->osd_evaluator,
+ (float *)positions,
+ 0,
+ num_basis_verts);
+ ss->osd_evaluator->refine(ss->osd_evaluator);
MEM_freeN(positions);
}
@@ -540,7 +521,7 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
for (S = 0; S < face->numVerts; S++) {
int x, y, k;
CCGEdge *edge = NULL;
- bool inverse_edge;
+ bool inverse_edge = false;
for (x = 0; x < gridSize; x++) {
for (y = 0; y < gridSize; y++) {
@@ -554,11 +535,12 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
ccgSubSurf__mapGridToFace(S, grid_u, grid_v, &face_u, &face_v);
/* TODO(sergey): Need proper port. */
- openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index,
- face_u, face_v,
- P,
- do_normals ? dPdu : NULL,
- do_normals ? dPdv : NULL);
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator, osd_face_index,
+ face_u, face_v,
+ P,
+ do_normals ? dPdu : NULL,
+ do_normals ? dPdv : NULL);
OSD_LOG("face=%d, corner=%d, grid_u=%f, grid_v=%f, face_u=%f, face_v=%f, P=(%f, %f, %f)\n",
osd_face_index, S, grid_u, grid_v, face_u, face_v, P[0], P[1], P[2]);
@@ -632,7 +614,11 @@ static void opensubdiv_evaluateQuadFaceGrids(CCGSubSurf *ss,
* let's just re-evaluate for simplicity.
*/
/* TODO(sergey): Need proper port. */
- openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index, u, v, P, dPdu, dPdv);
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator,
+ osd_face_index,
+ u, v,
+ P, dPdu, dPdv);
VertDataCopy(co, P, ss);
if (do_normals) {
cross_v3_v3v3(no, dPdu, dPdv);
@@ -696,7 +682,11 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
float P[3], dPdu[3], dPdv[3];
/* TODO(sergey): Need proper port. */
- openSubdiv_evaluateLimit(ss->osd_evaluator, osd_face_index + S, u, v, P, dPdu, dPdv);
+ ss->osd_evaluator->evaluateLimit(
+ ss->osd_evaluator,
+ osd_face_index + S,
+ u, v,
+ P, dPdu, dPdv);
OSD_LOG("face=%d, corner=%d, u=%f, v=%f, P=(%f, %f, %f)\n",
osd_face_index + S, S, u, v, P[0], P[1], P[2]);
@@ -739,7 +729,7 @@ static void opensubdiv_evaluateNGonFaceGrids(CCGSubSurf *ss,
/* Evaluate edges. */
for (S = 0; S < face->numVerts; S++) {
CCGEdge *edge = FACE_getEdges(face)[S];
- int x, S0, S1;
+ int x, S0 = 0, S1 = 0;
bool flip;
for (x = 0; x < face->numVerts; ++x) {
@@ -834,7 +824,12 @@ void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, DerivedMesh *dm)
OpenSubdiv_Converter converter;
ccgSubSurf_converter_setup_from_derivedmesh(ss, dm, &converter);
/* TODO(sergey): Remove possibly previously allocated refiner. */
- ss->osd_topology_refiner = openSubdiv_createTopologyRefinerDescr(&converter);
+ OpenSubdiv_TopologyRefinerSettings settings;
+ settings.level = ss->subdivLevels;
+ settings.is_adaptive = false;
+ ss->osd_topology_refiner =
+ openSubdiv_createTopologyRefinerFromConverter(
+ &converter, &settings);
ccgSubSurf_converter_free(&converter);
}
}
@@ -995,7 +990,7 @@ void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs)
void BKE_subsurf_osd_init(void)
{
- openSubdiv_init(GPU_legacy_support());
+ openSubdiv_init();
BLI_spin_init(&delete_spin);
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
index d6b15148ed1..0301582b303 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
@@ -84,6 +84,13 @@ static OpenSubdiv_SchemeType conv_dm_get_type(
return OSD_SCHEME_CATMARK;
}
+static OpenSubdiv_VtxBoundaryInterpolation
+conv_dm_get_vtx_boundary_interpolation(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
+}
+
static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation(
const OpenSubdiv_Converter *converter)
{
@@ -94,6 +101,12 @@ static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation(
return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
}
+static bool conv_dm_specifies_full_topology(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return true;
+}
+
static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter)
{
ConvDMStorage *storage = converter->user_data;
@@ -306,6 +319,20 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
#endif
}
+static bool conv_dm_is_infinite_sharp_vertex(
+ const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return false;
+}
+
+static float conv_dm_get_vertex_sharpness(
+ const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return 0.0f;
+}
+
static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter)
{
ConvDMStorage *storage = converter->user_data;
@@ -389,12 +416,6 @@ static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter)
return storage->num_uvs;
}
-static void conv_dm_get_uvs(const OpenSubdiv_Converter *converter, float *uvs)
-{
- ConvDMStorage *storage = converter->user_data;
- memcpy(uvs, storage->uvs, sizeof(float) * 2 * storage->num_uvs);
-}
-
static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
int face,
int corner)
@@ -432,35 +453,39 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
{
ConvDMStorage *user_data;
- converter->get_scheme_type = conv_dm_get_type;
+ converter->getSchemeType = conv_dm_get_type;
- converter->get_fvar_linear_interpolation =
+ converter->getVtxBoundaryInterpolation =
+ conv_dm_get_vtx_boundary_interpolation;
+ converter->getFVarLinearInterpolation =
conv_dm_get_fvar_linear_interpolation;
-
- converter->get_num_faces = conv_dm_get_num_faces;
- converter->get_num_edges = conv_dm_get_num_edges;
- converter->get_num_verts = conv_dm_get_num_verts;
-
- converter->get_num_face_verts = conv_dm_get_num_face_verts;
- converter->get_face_verts = conv_dm_get_face_verts;
- converter->get_face_edges = conv_dm_get_face_edges;
-
- converter->get_edge_verts = conv_dm_get_edge_verts;
- converter->get_num_edge_faces = conv_dm_get_num_edge_faces;
- converter->get_edge_faces = conv_dm_get_edge_faces;
- converter->get_edge_sharpness = conv_dm_get_edge_sharpness;
-
- converter->get_num_vert_edges = conv_dm_get_num_vert_edges;
- converter->get_vert_edges = conv_dm_get_vert_edges;
- converter->get_num_vert_faces = conv_dm_get_num_vert_faces;
- converter->get_vert_faces = conv_dm_get_vert_faces;
-
- converter->get_num_uv_layers = conv_dm_get_num_uv_layers;
- converter->precalc_uv_layer = conv_dm_precalc_uv_layer;
- converter->finish_uv_layer = conv_dm_finish_uv_layer;
- converter->get_num_uvs = conv_dm_get_num_uvs;
- converter->get_uvs = conv_dm_get_uvs;
- converter->get_face_corner_uv_index = conv_dm_get_face_corner_uv_index;
+ converter->specifiesFullTopology = conv_dm_specifies_full_topology;
+
+ converter->getNumFaces = conv_dm_get_num_faces;
+ converter->getNumEdges = conv_dm_get_num_edges;
+ converter->getNumVertices = conv_dm_get_num_verts;
+
+ converter->getNumFaceVertices = conv_dm_get_num_face_verts;
+ converter->getFaceVertices = conv_dm_get_face_verts;
+ converter->getFaceEdges = conv_dm_get_face_edges;
+
+ converter->getEdgeVertices = conv_dm_get_edge_verts;
+ converter->getNumEdgeFaces = conv_dm_get_num_edge_faces;
+ converter->getEdgeFaces = conv_dm_get_edge_faces;
+ converter->getEdgeSharpness = conv_dm_get_edge_sharpness;
+
+ converter->getNumVertexEdges = conv_dm_get_num_vert_edges;
+ converter->getVertexEdges = conv_dm_get_vert_edges;
+ converter->getNumVertexFaces = conv_dm_get_num_vert_faces;
+ converter->getVertexFaces = conv_dm_get_vert_faces;
+ converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex;
+ converter->getVertexSharpness = conv_dm_get_vertex_sharpness;
+
+ converter->getNumUVLayers = conv_dm_get_num_uv_layers;
+ converter->precalcUVLayer = conv_dm_precalc_uv_layer;
+ converter->finishUVLayer = conv_dm_finish_uv_layer;
+ converter->getNumUVCoordinates = conv_dm_get_num_uvs;
+ converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index;
user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
user_data->ss = ss;
@@ -476,7 +501,7 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
user_data->uvs = NULL;
user_data->face_uvs = NULL;
- converter->free_user_data = conv_dm_free_user_data;
+ converter->freeUserData = conv_dm_free_user_data;
converter->user_data = user_data;
#ifdef USE_MESH_ELEMENT_MAPPING
@@ -530,6 +555,13 @@ static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(
}
}
+static OpenSubdiv_VtxBoundaryInterpolation
+conv_ccg_get_vtx_boundary_interpolation(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
+}
+
static OpenSubdiv_FVarLinearInterpolation
conv_ccg_get_fvar_linear_interpolation(const OpenSubdiv_Converter *converter)
{
@@ -540,6 +572,12 @@ conv_ccg_get_fvar_linear_interpolation(const OpenSubdiv_Converter *converter)
return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
}
+static bool conv_ccg_specifies_full_topology(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return true;
+}
+
static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter)
{
CCGSubSurf *ss = converter->user_data;
@@ -683,6 +721,20 @@ static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter,
}
}
+static bool conv_ccg_is_infinite_sharp_vertex(
+ const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return false;
+}
+
+static float conv_ccg_get_vertex_sharpness(
+ const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return 0.0f;
+}
+
static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter))
{
return 0;
@@ -702,11 +754,6 @@ static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter))
return 0;
}
-static void conv_ccg_get_uvs(const OpenSubdiv_Converter * UNUSED(converter),
- float *UNUSED(uvs))
-{
-}
-
static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter),
int UNUSED(face),
int UNUSED(corner_))
@@ -717,45 +764,49 @@ static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(
void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
OpenSubdiv_Converter *converter)
{
- converter->get_scheme_type = conv_ccg_get_bilinear_type;
+ converter->getSchemeType = conv_ccg_get_bilinear_type;
- converter->get_fvar_linear_interpolation =
+ converter->getVtxBoundaryInterpolation =
+ conv_ccg_get_vtx_boundary_interpolation;
+ converter->getFVarLinearInterpolation =
conv_ccg_get_fvar_linear_interpolation;
-
- converter->get_num_faces = conv_ccg_get_num_faces;
- converter->get_num_edges = conv_ccg_get_num_edges;
- converter->get_num_verts = conv_ccg_get_num_verts;
-
- converter->get_num_face_verts = conv_ccg_get_num_face_verts;
- converter->get_face_verts = conv_ccg_get_face_verts;
- converter->get_face_edges = conv_ccg_get_face_edges;
-
- converter->get_edge_verts = conv_ccg_get_edge_verts;
- converter->get_num_edge_faces = conv_ccg_get_num_edge_faces;
- converter->get_edge_faces = conv_ccg_get_edge_faces;
- converter->get_edge_sharpness = conv_ccg_get_edge_sharpness;
-
- converter->get_num_vert_edges = conv_ccg_get_num_vert_edges;
- converter->get_vert_edges = conv_ccg_get_vert_edges;
- converter->get_num_vert_faces = conv_ccg_get_num_vert_faces;
- converter->get_vert_faces = conv_ccg_get_vert_faces;
-
- converter->get_num_uv_layers = conv_ccg_get_num_uv_layers;
- converter->precalc_uv_layer = conv_ccg_precalc_uv_layer;
- converter->finish_uv_layer = conv_ccg_finish_uv_layer;
- converter->get_num_uvs = conv_ccg_get_num_uvs;
- converter->get_uvs = conv_ccg_get_uvs;
- converter->get_face_corner_uv_index = conv_ccg_get_face_corner_uv_index;
-
- converter->free_user_data = NULL;
+ converter->specifiesFullTopology = conv_ccg_specifies_full_topology;
+
+ converter->getNumFaces = conv_ccg_get_num_faces;
+ converter->getNumEdges = conv_ccg_get_num_edges;
+ converter->getNumVertices = conv_ccg_get_num_verts;
+
+ converter->getNumFaceVertices = conv_ccg_get_num_face_verts;
+ converter->getFaceVertices = conv_ccg_get_face_verts;
+ converter->getFaceEdges = conv_ccg_get_face_edges;
+
+ converter->getEdgeVertices = conv_ccg_get_edge_verts;
+ converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces;
+ converter->getEdgeFaces = conv_ccg_get_edge_faces;
+ converter->getEdgeSharpness = conv_ccg_get_edge_sharpness;
+
+ converter->getNumVertexEdges = conv_ccg_get_num_vert_edges;
+ converter->getVertexEdges = conv_ccg_get_vert_edges;
+ converter->getNumVertexFaces = conv_ccg_get_num_vert_faces;
+ converter->getVertexFaces = conv_ccg_get_vert_faces;
+ converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex;
+ converter->getVertexSharpness = conv_ccg_get_vertex_sharpness;
+
+ converter->getNumUVLayers = conv_ccg_get_num_uv_layers;
+ converter->precalcUVLayer = conv_ccg_precalc_uv_layer;
+ converter->finishUVLayer = conv_ccg_finish_uv_layer;
+ converter->getNumUVCoordinates = conv_ccg_get_num_uvs;
+ converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index;
+
+ converter->freeUserData = NULL;
converter->user_data = ss;
}
void ccgSubSurf_converter_free(
struct OpenSubdiv_Converter *converter)
{
- if (converter->free_user_data) {
- converter->free_user_data(converter);
+ if (converter->freeUserData) {
+ converter->freeUserData(converter);
}
}
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index e099ceaea53..1d787388774 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -55,32 +55,29 @@
#include "BKE_colorband.h"
#include "BKE_editmesh.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_tangent.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_multires.h"
#include "BKE_bvhutils.h"
#include "BKE_deform.h"
-#include "BKE_global.h" /* For debug flag, DM_update_tessface_data() func. */
-
-#ifdef WITH_GAMEENGINE
-#include "BKE_navmesh_conversion.h"
-static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
-#endif
#include "BLI_sys_types.h" /* for intptr_t support */
-#include "GPU_buffers.h"
-#include "GPU_glew.h"
-#include "GPU_shader.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+#include "BKE_shrinkwrap.h"
#ifdef WITH_OPENSUBDIV
-# include "BKE_depsgraph.h"
# include "DNA_userdef_types.h"
#endif
@@ -89,17 +86,20 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#ifdef USE_MODIFIER_VALIDATE
# define ASSERT_IS_VALID_DM(dm) (BLI_assert((dm == NULL) || (DM_is_valid(dm) == true)))
+# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
#else
# define ASSERT_IS_VALID_DM(dm)
+# define ASSERT_IS_VALID_MESH(mesh)
#endif
static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
-static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob);
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
+static void mesh_init_origspace(Mesh *mesh);
+
/* -------------------------------------------------------------------- */
@@ -327,7 +327,7 @@ void DM_init_funcs(DerivedMesh *dm)
dm->getPolyDataArray = DM_get_poly_data_layer;
dm->getLoopDataArray = DM_get_loop_data_layer;
- bvhcache_init(&dm->bvhCache);
+ dm->bvhCache = NULL;
}
/**
@@ -349,7 +349,6 @@ void DM_init(
DM_init_funcs(dm);
dm->needsFree = 1;
- dm->auto_bump_scale = -1.0f;
dm->dirty = 0;
/* don't use CustomData_reset(...); because we dont want to touch customdata */
@@ -406,7 +405,6 @@ int DM_release(DerivedMesh *dm)
{
if (dm->needsFree) {
bvhcache_free(&dm->bvhCache);
- GPU_drawobject_free(dm);
CustomData_free(&dm->vertData, dm->numVertData);
CustomData_free(&dm->edgeData, dm->numEdgeData);
CustomData_free(&dm->faceData, dm->numTessFaceData);
@@ -466,39 +464,6 @@ void DM_ensure_normals(DerivedMesh *dm)
BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
}
-static void DM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, float split_angle)
-{
- dm->calcLoopNormals(dm, use_split_normals, split_angle);
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
-}
-
-/* note: until all modifiers can take MPoly's as input,
- * use this at the start of modifiers */
-void DM_ensure_tessface(DerivedMesh *dm)
-{
- const int numTessFaces = dm->getNumTessFaces(dm);
- const int numPolys = dm->getNumPolys(dm);
-
- if ((numTessFaces == 0) && (numPolys != 0)) {
- dm->recalcTessellation(dm);
-
- if (dm->getNumTessFaces(dm) != 0) {
- /* printf("info %s: polys -> ngons calculated\n", __func__); */
- }
- else {
- printf("warning %s: could not create tessfaces from %d polygons, dm->type=%u\n",
- __func__, numPolys, dm->type);
- }
- }
-
- else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
- BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX) || numTessFaces == 0);
- DM_update_tessface_data(dm);
- }
-
- dm->dirty &= ~DM_DIRTY_TESS_CDLAYERS;
-}
-
/**
* Ensure the array is large enough
*
@@ -533,195 +498,13 @@ void DM_ensure_looptri_data(DerivedMesh *dm)
}
}
-void DM_verttri_from_looptri(MVertTri *verttri, const MLoop *mloop, const MLoopTri *looptri, int looptri_num)
-{
- int i;
- for (i = 0; i < looptri_num; i++) {
- verttri[i].tri[0] = mloop[looptri[i].tri[0]].v;
- verttri[i].tri[1] = mloop[looptri[i].tri[1]].v;
- verttri[i].tri[2] = mloop[looptri[i].tri[2]].v;
- }
-}
-
-/* Update tessface CD data from loop/poly ones. Needed when not retessellating after modstack evaluation. */
-/* NOTE: Assumes dm has valid tessellated data! */
-void DM_update_tessface_data(DerivedMesh *dm)
-{
- MFace *mf, *mface = dm->getTessFaceArray(dm);
- MPoly *mp = dm->getPolyArray(dm);
- MLoop *ml = dm->getLoopArray(dm);
-
- CustomData *fdata = dm->getTessFaceDataLayout(dm);
- CustomData *pdata = dm->getPolyDataLayout(dm);
- CustomData *ldata = dm->getLoopDataLayout(dm);
-
- const int totface = dm->getNumTessFaces(dm);
- int mf_idx;
-
- int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
- unsigned int (*loopindex)[4];
-
- /* Should never occur, but better abort than segfault! */
- if (!polyindex)
- return;
-
- CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
-
- if (CustomData_has_layer(fdata, CD_MTFACE) ||
- CustomData_has_layer(fdata, CD_MCOL) ||
- CustomData_has_layer(fdata, CD_PREVIEW_MCOL) ||
- CustomData_has_layer(fdata, CD_ORIGSPACE) ||
- CustomData_has_layer(fdata, CD_TESSLOOPNORMAL) ||
- CustomData_has_layer(fdata, CD_TANGENT))
- {
- loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__);
-
- for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
- const int mf_len = mf->v4 ? 4 : 3;
- unsigned int *ml_idx = loopindex[mf_idx];
- int i, not_done;
-
- /* Find out loop indices. */
- /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
- for (i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
- const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
- if (tf_v != -1) {
- ml_idx[tf_v] = i;
- not_done--;
- }
- }
- }
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
- * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
- * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
- */
- BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, mface, polyindex, loopindex, totface);
-
- MEM_freeN(loopindex);
- }
-
- if (G.debug & G_DEBUG)
- printf("%s: Updated tessellated customdata of dm %p\n", __func__, dm);
-
- dm->dirty &= ~DM_DIRTY_TESS_CDLAYERS;
-}
-
-void DM_generate_tangent_tessface_data(DerivedMesh *dm, bool generate)
-{
- MFace *mf, *mface = dm->getTessFaceArray(dm);
- MPoly *mp = dm->getPolyArray(dm);
- MLoop *ml = dm->getLoopArray(dm);
-
- CustomData *fdata = dm->getTessFaceDataLayout(dm);
- CustomData *pdata = dm->getPolyDataLayout(dm);
- CustomData *ldata = dm->getLoopDataLayout(dm);
-
- const int totface = dm->getNumTessFaces(dm);
- int mf_idx;
-
- int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
- unsigned int (*loopindex)[4] = NULL;
-
- /* Should never occur, but better abort than segfault! */
- if (!polyindex)
- return;
-
- if (generate) {
- for (int j = 0; j < ldata->totlayer; j++) {
- if (ldata->layers[j].type == CD_TANGENT) {
- CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, totface, ldata->layers[j].name);
- CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
-
- if (!loopindex) {
- loopindex = MEM_malloc_arrayN(totface, sizeof(*loopindex), __func__);
- for (mf_idx = 0, mf = mface; mf_idx < totface; mf_idx++, mf++) {
- const int mf_len = mf->v4 ? 4 : 3;
- unsigned int *ml_idx = loopindex[mf_idx];
-
- /* Find out loop indices. */
- /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
- for (int i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
- const int tf_v = BKE_MESH_TESSFACE_VINDEX_ORDER(mf, ml[i].v);
- if (tf_v != -1) {
- ml_idx[tf_v] = i;
- not_done--;
- }
- }
- }
- }
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * Here, our tfaces' fourth vertex index is never 0 for a quad. However, we know our fourth loop index may be
- * 0 for quads (because our quads may have been rotated compared to their org poly, see tessellation code).
- * So we pass the MFace's, and BKE_mesh_loops_to_tessdata will use MFace->v4 index as quad test.
- */
- BKE_mesh_tangent_loops_to_tessdata(fdata, ldata, mface, polyindex, loopindex, totface, ldata->layers[j].name);
- }
- }
- if (loopindex)
- MEM_freeN(loopindex);
- BLI_assert(CustomData_from_bmeshpoly_test(fdata, pdata, ldata, true));
- }
-
- if (G.debug & G_DEBUG)
- printf("%s: Updated tessellated tangents of dm %p\n", __func__, dm);
-}
-
-
-void DM_update_materials(DerivedMesh *dm, Object *ob)
-{
- int i, totmat = ob->totcol + 1; /* materials start from 1, default material is 0 */
-
- if (dm->totmat != totmat) {
- dm->totmat = totmat;
- /* invalidate old materials */
- if (dm->mat)
- MEM_freeN(dm->mat);
-
- dm->mat = MEM_malloc_arrayN(totmat, sizeof(*dm->mat), "DerivedMesh.mat");
- }
-
- /* we leave last material as empty - rationale here is being able to index
- * the materials by using the mf->mat_nr directly and leaving the last
- * material as NULL in case no materials exist on mesh, so indexing will not fail */
- for (i = 0; i < totmat - 1; i++) {
- dm->mat[i] = give_current_material(ob, i + 1);
- }
- dm->mat[i] = NULL;
-}
-
-MLoopUV *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr)
-{
- MLoopUV *uv_base;
-
- BLI_assert(mat_nr < dm->totmat);
-
- if (dm->mat[mat_nr] && dm->mat[mat_nr]->texpaintslot &&
- dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname)
- {
- uv_base = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV,
- dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname);
- /* This can fail if we have changed the name in the UV layer list and have assigned the old name in the material
- * texture slot.*/
- if (!uv_base)
- uv_base = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
- }
- else {
- uv_base = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
- }
-
- return uv_base;
-}
-
void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool take_ownership)
{
/* dm might depend on me, so we need to do everything with a local copy */
Mesh tmp = *me;
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
int did_shapekeys = 0;
- int alloctype = CD_DUPLICATE;
+ eCDAllocType alloctype = CD_DUPLICATE;
if (take_ownership && dm->type == DM_TYPE_CDDM && dm->needsFree) {
bool has_any_referenced_layers =
@@ -754,6 +537,7 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
CustomData_copy(&dm->loopData, &tmp.ldata, mask, alloctype, totloop);
CustomData_copy(&dm->polyData, &tmp.pdata, mask, alloctype, totpoly);
tmp.cd_flag = dm->cd_flag;
+ tmp.runtime.deformed_only = dm->deformedOnly;
if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) {
KeyBlock *kb;
@@ -831,8 +615,9 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
* stack */
if (tmp.totvert != me->totvert && !did_shapekeys && me->key) {
printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name);
- if (tmp.key)
+ if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
id_us_min(&tmp.key->id);
+ }
tmp.key = NULL;
}
@@ -859,26 +644,18 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask, bool
}
}
-void DM_to_meshkey(DerivedMesh *dm, Mesh *me, KeyBlock *kb)
+/** Utility function to convert an (evaluated) Mesh to a shape key block. */
+/* Just a shallow wrapper around BKE_keyblock_convert_from_mesh,
+ * that ensures both evaluated mesh and original one has same number of vertices. */
+void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *me, KeyBlock *kb)
{
- int a, totvert = dm->getNumVerts(dm);
- float *fp;
- MVert *mvert;
+ const int totvert = me_deformed->totvert;
if (totvert == 0 || me->totvert == 0 || me->totvert != totvert) {
return;
}
- if (kb->data) MEM_freeN(kb->data);
- kb->data = MEM_malloc_arrayN(me->key->elemsize, me->totvert, "kb->data");
- kb->totelem = totvert;
-
- fp = kb->data;
- mvert = dm->getVertDataArray(dm, CD_MVERT);
-
- for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) {
- copy_v3_v3(fp, mvert->co);
- }
+ BKE_keyblock_convert_from_mesh(me_deformed, me->key, kb);
}
/**
@@ -900,27 +677,41 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask)
#endif
}
-void DM_add_vert_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+static void mesh_set_only_copy(Mesh *mesh, CustomDataMask mask)
+{
+ CustomData_set_only_copy(&mesh->vdata, mask);
+ CustomData_set_only_copy(&mesh->edata, mask);
+ CustomData_set_only_copy(&mesh->fdata, mask);
+ /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
+ * weight paint mode when there are modifiers applied, needs further investigation,
+ * see replies to r50969, Campbell */
+#if 0
+ CustomData_set_only_copy(&mesh->ldata, mask);
+ CustomData_set_only_copy(&mesh->pdata, mask);
+#endif
+}
+
+void DM_add_vert_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->vertData, type, alloctype, layer, dm->numVertData);
}
-void DM_add_edge_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_edge_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
}
-void DM_add_tessface_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_tessface_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numTessFaceData);
}
-void DM_add_loop_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData);
}
-void DM_add_poly_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+void DM_add_poly_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
{
CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData);
}
@@ -1109,11 +900,6 @@ void DM_interp_tessface_data(
weights, (float *)vert_weights, count, dest_index);
}
-void DM_swap_tessface_data(DerivedMesh *dm, int index, const int *corner_indices)
-{
- CustomData_swap_corners(&dm->faceData, index, corner_indices);
-}
-
void DM_interp_loop_data(
DerivedMesh *source, DerivedMesh *dest,
int *src_indices,
@@ -1146,56 +932,6 @@ DerivedMesh *mesh_create_derived(Mesh *me, float (*vertCos)[3])
return dm;
}
-DerivedMesh *mesh_create_derived_for_modifier(
- Scene *scene, Object *ob,
- ModifierData *md, int build_shapekey_layers)
-{
- Mesh *me = ob->data;
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- DerivedMesh *dm;
- KeyBlock *kb;
-
- md->scene = scene;
-
- if (!(md->mode & eModifierMode_Realtime)) {
- return NULL;
- }
-
- if (mti->isDisabled && mti->isDisabled(md, 0)) {
- return NULL;
- }
-
- if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) {
- BKE_keyblock_convert_to_mesh(kb, me);
- }
-
- if (mti->type == eModifierTypeType_OnlyDeform) {
- int numVerts;
- float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts);
-
- modwrap_deformVerts(md, ob, NULL, deformedVerts, numVerts, 0);
- dm = mesh_create_derived(me, deformedVerts);
-
- if (build_shapekey_layers)
- add_shapekey_layers(dm, me, ob);
-
- MEM_freeN(deformedVerts);
- }
- else {
- DerivedMesh *tdm = mesh_create_derived(me, NULL);
-
- if (build_shapekey_layers)
- add_shapekey_layers(tdm, me, ob);
-
- dm = modwrap_applyModifier(md, ob, tdm, 0);
- ASSERT_IS_VALID_DM(dm);
-
- if (tdm != dm) tdm->release(tdm);
- }
-
- return dm;
-}
-
static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
{
BMIter iter;
@@ -1216,7 +952,7 @@ static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
}
/* orco custom data layer */
-static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *free))[3]
+static float (*get_orco_coords(Object *ob, BMEditMesh *em, int layer, int *free))[3]
{
*free = 0;
@@ -1247,386 +983,77 @@ static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *fr
return NULL;
}
-static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, BMEditMesh *em, int layer)
+static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
{
- DerivedMesh *dm;
+ Mesh *mesh;
float (*orco)[3];
int free;
if (em) {
- dm = CDDM_from_editbmesh(em, false, false);
+ mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0);
}
else {
- dm = CDDM_from_mesh(me);
+ mesh = BKE_mesh_copy_for_eval(me, true);
}
- orco = get_orco_coords_dm(ob, em, layer, &free);
+ orco = get_orco_coords(ob, em, layer, &free);
if (orco) {
- CDDM_apply_vert_coords(dm, orco);
+ BKE_mesh_apply_vert_coords(mesh, orco);
if (free) MEM_freeN(orco);
}
- return dm;
+ return mesh;
}
-static void add_orco_dm(
- Object *ob, BMEditMesh *em, DerivedMesh *dm,
- DerivedMesh *orcodm, int layer)
+static void add_orco_mesh(
+ Object *ob, BMEditMesh *em, Mesh *mesh,
+ Mesh *me_orco, int layer)
{
float (*orco)[3], (*layerorco)[3];
int totvert, free;
- totvert = dm->getNumVerts(dm);
+ totvert = mesh->totvert;
- if (orcodm) {
- orco = MEM_calloc_arrayN(totvert, sizeof(float[3]), "dm orco");
+ if (me_orco) {
free = 1;
- if (orcodm->getNumVerts(orcodm) == totvert)
- orcodm->getVertCos(orcodm, orco);
- else
- dm->getVertCos(dm, orco);
- }
- else
- orco = get_orco_coords_dm(ob, em, layer, &free);
-
- if (orco) {
- if (layer == CD_ORCO)
- BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0);
-
- if (!(layerorco = DM_get_vert_data_layer(dm, layer))) {
- DM_add_vert_layer(dm, layer, CD_CALLOC, NULL);
- layerorco = DM_get_vert_data_layer(dm, layer);
- }
-
- memcpy(layerorco, orco, sizeof(float) * 3 * totvert);
- if (free) MEM_freeN(orco);
- }
-}
-
-/* weight paint colors */
-
-/* Something of a hack, at the moment deal with weightpaint
- * by tucking into colors during modifier eval, only in
- * wpaint mode. Works ok but need to make sure recalc
- * happens on enter/exit wpaint.
- */
-
-void weight_to_rgb(float r_rgb[3], const float weight)
-{
- const float blend = ((weight / 2.0f) + 0.5f);
-
- if (weight <= 0.25f) { /* blue->cyan */
- r_rgb[0] = 0.0f;
- r_rgb[1] = blend * weight * 4.0f;
- r_rgb[2] = blend;
- }
- else if (weight <= 0.50f) { /* cyan->green */
- r_rgb[0] = 0.0f;
- r_rgb[1] = blend;
- r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
- }
- else if (weight <= 0.75f) { /* green->yellow */
- r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
- r_rgb[1] = blend;
- r_rgb[2] = 0.0f;
- }
- else if (weight <= 1.0f) { /* yellow->red */
- r_rgb[0] = blend;
- r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
- r_rgb[2] = 0.0f;
- }
- else {
- /* exceptional value, unclamped or nan,
- * avoid uninitialized memory use */
- r_rgb[0] = 1.0f;
- r_rgb[1] = 0.0f;
- r_rgb[2] = 1.0f;
- }
-}
-
-/* draw_flag's for calc_weightpaint_vert_color */
-enum {
- /* only one of these should be set, keep first (for easy bit-shifting) */
- CALC_WP_GROUP_USER_ACTIVE = (1 << 1),
- CALC_WP_GROUP_USER_ALL = (1 << 2),
-
- CALC_WP_MULTIPAINT = (1 << 3),
- CALC_WP_AUTO_NORMALIZE = (1 << 4),
- CALC_WP_MIRROR_X = (1 << 5),
-};
-
-typedef struct DMWeightColorInfo {
- const ColorBand *coba;
- const char *alert_color;
-} DMWeightColorInfo;
-
-
-static int dm_drawflag_calc(const ToolSettings *ts, const Mesh *me)
-{
- return ((ts->multipaint ? CALC_WP_MULTIPAINT : 0) |
- /* CALC_WP_GROUP_USER_ACTIVE or CALC_WP_GROUP_USER_ALL */
- (1 << ts->weightuser) |
- (ts->auto_normalize ? CALC_WP_AUTO_NORMALIZE : 0) |
- ((me->editflag & ME_EDIT_MIRROR_X) ? CALC_WP_MIRROR_X : 0));
-}
-
-static void weightpaint_color(unsigned char r_col[4], DMWeightColorInfo *dm_wcinfo, const float input)
-{
- float colf[4];
-
- if (dm_wcinfo && dm_wcinfo->coba) {
- BKE_colorband_evaluate(dm_wcinfo->coba, input, colf);
- }
- else {
- weight_to_rgb(colf, input);
- }
-
- /* don't use rgb_float_to_uchar() here because
- * the resulting float doesn't need 0-1 clamp check */
- r_col[0] = (unsigned char)(colf[0] * 255.0f);
- r_col[1] = (unsigned char)(colf[1] * 255.0f);
- r_col[2] = (unsigned char)(colf[2] * 255.0f);
- r_col[3] = 255;
-}
-
-
-static void calc_weightpaint_vert_color(
- unsigned char r_col[4],
- const MDeformVert *dv,
- DMWeightColorInfo *dm_wcinfo,
- const int defbase_tot, const int defbase_act,
- const bool *defbase_sel, const int defbase_sel_tot,
- const int draw_flag)
-{
- float input = 0.0f;
-
- bool show_alert_color = false;
-
- if ((defbase_sel_tot > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
- /* Multi-Paint feature */
- input = BKE_defvert_multipaint_collective_weight(
- dv, defbase_tot, defbase_sel, defbase_sel_tot, (draw_flag & CALC_WP_AUTO_NORMALIZE) != 0);
-
- /* make it black if the selected groups have no weight on a vertex */
- if (input == 0.0f) {
- show_alert_color = true;
- }
- }
- else {
- /* default, non tricky behavior */
- input = defvert_find_weight(dv, defbase_act);
-
- if (draw_flag & CALC_WP_GROUP_USER_ACTIVE) {
- if (input == 0.0f) {
- show_alert_color = true;
- }
- }
- else if (draw_flag & CALC_WP_GROUP_USER_ALL) {
- if (input == 0.0f) {
- show_alert_color = defvert_is_weight_zero(dv, defbase_tot);
- }
- }
- }
-
- if (show_alert_color == false) {
- CLAMP(input, 0.0f, 1.0f);
- weightpaint_color(r_col, dm_wcinfo, input);
- }
- else {
- copy_v3_v3_char((char *)r_col, dm_wcinfo->alert_color);
- r_col[3] = 255;
- }
-}
-
-static DMWeightColorInfo G_dm_wcinfo;
-
-void vDM_ColorBand_store(const ColorBand *coba, const char alert_color[4])
-{
- G_dm_wcinfo.coba = coba;
- G_dm_wcinfo.alert_color = alert_color;
-}
-
-/**
- * return an array of vertex weight colors, caller must free.
- *
- * \note that we could save some memory and allocate RGB only but then we'd need to
- * re-arrange the colors when copying to the face since MCol has odd ordering,
- * so leave this as is - campbell
- */
-static void calc_weightpaint_vert_array(
- Object *ob, DerivedMesh *dm, int const draw_flag, DMWeightColorInfo *dm_wcinfo,
- unsigned char (*r_wtcol_v)[4])
-{
- BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL;
- const int numVerts = dm->getNumVerts(dm);
-
- if ((ob->actdef != 0) &&
- (CustomData_has_layer(em ? &em->bm->vdata : &dm->vertData, CD_MDEFORMVERT)))
- {
- unsigned char (*wc)[4] = r_wtcol_v;
- unsigned int i;
-
- /* variables for multipaint */
- const int defbase_tot = BLI_listbase_count(&ob->defbase);
- const int defbase_act = ob->actdef - 1;
-
- int defbase_sel_tot = 0;
- bool *defbase_sel = NULL;
-
- if (draw_flag & CALC_WP_MULTIPAINT) {
- defbase_sel = BKE_object_defgroup_selected_get(ob, defbase_tot, &defbase_sel_tot);
-
- if (defbase_sel_tot > 1 && (draw_flag & CALC_WP_MIRROR_X)) {
- BKE_object_defgroup_mirror_selection(ob, defbase_tot, defbase_sel, defbase_sel, &defbase_sel_tot);
- }
- }
-
- /* editmesh won't have deform verts unless modifiers require it,
- * avoid having to create an array of deform-verts only for drawing
- * by reading from the bmesh directly. */
- if (em) {
- BMIter iter;
- BMVert *eve;
- const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
- BLI_assert(cd_dvert_offset != -1);
-
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- calc_weightpaint_vert_color(
- (unsigned char *)wc, dv, dm_wcinfo,
- defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
- wc++;
- }
+ if (me_orco->totvert == totvert) {
+ orco = BKE_mesh_vertexCos_get(me_orco, NULL);
}
else {
- const MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
- for (i = numVerts; i != 0; i--, wc++, dv++) {
- calc_weightpaint_vert_color(
- (unsigned char *)wc, dv, dm_wcinfo,
- defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
- }
- }
-
- if (defbase_sel) {
- MEM_freeN(defbase_sel);
+ orco = BKE_mesh_vertexCos_get(mesh, NULL);
}
}
else {
- unsigned char col[4];
- if ((ob->actdef == 0) && !BLI_listbase_is_empty(&ob->defbase)) {
- /* color-code for missing data (full brightness isn't easy on the eye). */
- ARRAY_SET_ITEMS(col, 0xa0, 0, 0xa0, 0xff);
- }
- else if (draw_flag & (CALC_WP_GROUP_USER_ACTIVE | CALC_WP_GROUP_USER_ALL)) {
- copy_v3_v3_char((char *)col, dm_wcinfo->alert_color);
- col[3] = 255;
- }
- else {
- weightpaint_color(col, dm_wcinfo, 0.0f);
- }
- copy_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
+ /* TODO(sybren): totvert should potentially change here, as ob->data
+ * or em may have a different number of vertices than dm. */
+ orco = get_orco_coords(ob, em, layer, &free);
}
-}
-/** return an array of vertex weight colors from given weights, caller must free.
- *
- * \note that we could save some memory and allocate RGB only but then we'd need to
- * re-arrange the colors when copying to the face since MCol has odd ordering,
- * so leave this as is - campbell
- */
-static void calc_colors_from_weights_array(
- const int num, const float *weights,
- unsigned char (*r_wtcol_v)[4])
-{
- unsigned char (*wc)[4] = r_wtcol_v;
- int i;
-
- for (i = 0; i < num; i++, wc++, weights++) {
- weightpaint_color((unsigned char *)wc, NULL, *weights);
- }
-}
-
-void DM_update_weight_mcol(
- Object *ob, DerivedMesh *dm, int const draw_flag,
- float *weights, int num, const int *indices)
-{
- BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL;
- unsigned char (*wtcol_v)[4];
- int numVerts = dm->getNumVerts(dm);
- int i;
-
- if (em) {
- BKE_editmesh_color_ensure(em, BM_VERT);
- wtcol_v = em->derivedVertColor;
- }
- else {
- wtcol_v = MEM_malloc_arrayN(numVerts, sizeof(*wtcol_v), __func__);
- }
-
- /* Weights are given by caller. */
- if (weights) {
- float *w = weights;
- /* If indices is not NULL, it means we do not have weights for all vertices,
- * so we must create them (and set them to zero)... */
- if (indices) {
- w = MEM_calloc_arrayN(numVerts, sizeof(float), "Temp weight array DM_update_weight_mcol");
- i = num;
- while (i--)
- w[indices[i]] = weights[i];
- }
-
- /* Convert float weights to colors. */
- calc_colors_from_weights_array(numVerts, w, wtcol_v);
-
- if (indices)
- MEM_freeN(w);
- }
- else {
- /* No weights given, take them from active vgroup(s). */
- calc_weightpaint_vert_array(ob, dm, draw_flag, &G_dm_wcinfo, wtcol_v);
- }
-
- if (dm->type == DM_TYPE_EDITBMESH) {
- /* editmesh draw function checks specifically for this */
- }
- else {
- const int dm_totpoly = dm->getNumPolys(dm);
- const int dm_totloop = dm->getNumLoops(dm);
- unsigned char(*wtcol_l)[4] = CustomData_get_layer(dm->getLoopDataLayout(dm), CD_PREVIEW_MLOOPCOL);
- MLoop *mloop = dm->getLoopArray(dm), *ml;
- MPoly *mp = dm->getPolyArray(dm);
- int l_index;
- int j;
-
- /* now add to loops, so the data can be passed through the modifier stack
- * If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
- if (!wtcol_l) {
- wtcol_l = MEM_malloc_arrayN(dm_totloop, sizeof(*wtcol_l), __func__);
- CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, dm_totloop);
+ if (orco) {
+ if (layer == CD_ORCO) {
+ BKE_mesh_orco_verts_transform(ob->data, orco, totvert, 0);
}
- l_index = 0;
- for (i = 0; i < dm_totpoly; i++, mp++) {
- ml = mloop + mp->loopstart;
+ if (!(layerorco = CustomData_get_layer(&mesh->vdata, layer))) {
+ CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, NULL, mesh->totvert);
+ BKE_mesh_update_customdata_pointers(mesh, false);
- for (j = 0; j < mp->totloop; j++, ml++, l_index++) {
- copy_v4_v4_uchar(&wtcol_l[l_index][0],
- &wtcol_v[ml->v][0]);
- }
+ layerorco = CustomData_get_layer(&mesh->vdata, layer);
}
- MEM_freeN(wtcol_v);
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ memcpy(layerorco, orco, sizeof(float) * 3 * totvert);
+ if (free) MEM_freeN(orco);
}
}
-static void DM_update_statvis_color(const Scene *scene, Object *ob, DerivedMesh *dm)
+static void editmesh_update_statvis_color(const Scene *scene, Object *ob)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
-
- BKE_editmesh_statvis_calc(em, dm, &scene->toolsettings->statvis);
+ Mesh *me = ob->data;
+ BKE_mesh_runtime_ensure_edit_data(me);
+ BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
}
static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid)
@@ -1685,20 +1112,20 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape
}
}
-static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
+static void add_shapekey_layers(Mesh *me_dst, Mesh *me_src, Object *UNUSED(ob))
{
KeyBlock *kb;
- Key *key = me->key;
+ Key *key = me_src->key;
int i;
- if (!me->key)
+ if (!me_src->key)
return;
/* ensure we can use mesh vertex count for derived mesh custom data */
- if (me->totvert != dm->getNumVerts(dm)) {
+ if (me_src->totvert != me_dst->totvert) {
fprintf(stderr,
- "%s: vertex size mismatch (mesh/dm) '%s' (%d != %d)\n",
- __func__, me->id.name + 2, me->totvert, dm->getNumVerts(dm));
+ "%s: vertex size mismatch (mesh/eval) '%s' (%d != %d)\n",
+ __func__, me_src->id.name + 2, me_src->totvert, me_dst->totvert);
return;
}
@@ -1706,131 +1133,79 @@ static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
int ci;
float *array;
- if (me->totvert != kb->totelem) {
+ if (me_src->totvert != kb->totelem) {
fprintf(stderr,
"%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n",
- __func__, me->id.name + 2, me->totvert, kb->name, kb->totelem);
- array = MEM_calloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__);
+ __func__, me_src->id.name + 2, me_src->totvert, kb->name, kb->totelem);
+ array = MEM_calloc_arrayN((size_t)me_src->totvert, sizeof(float[3]), __func__);
}
else {
- array = MEM_malloc_arrayN((size_t)me->totvert, 3 * sizeof(float), __func__);
- memcpy(array, kb->data, (size_t)me->totvert * 3 * sizeof(float));
+ array = MEM_malloc_arrayN((size_t)me_src->totvert, sizeof(float[3]), __func__);
+ memcpy(array, kb->data, (size_t)me_src->totvert * sizeof(float[3]));
}
- CustomData_add_layer_named(&dm->vertData, CD_SHAPEKEY, CD_ASSIGN, array, dm->numVertData, kb->name);
- ci = CustomData_get_layer_index_n(&dm->vertData, CD_SHAPEKEY, i);
+ CustomData_add_layer_named(&me_dst->vdata, CD_SHAPEKEY, CD_ASSIGN, array, me_dst->totvert, kb->name);
+ ci = CustomData_get_layer_index_n(&me_dst->vdata, CD_SHAPEKEY, i);
- dm->vertData.layers[ci].uid = kb->uid;
+ me_dst->vdata.layers[ci].uid = kb->uid;
}
}
-/**
- * Called after calculating all modifiers.
- *
- * \note tessfaces should already be calculated.
- */
-static void dm_ensure_display_normals(DerivedMesh *dm)
-{
- /* Note: dm *may* have a poly CD_NORMAL layer (generated by a modifier needing poly normals e.g.).
- * We do not use it here, though. And it should be tagged as temp!
- */
- /* BLI_assert((CustomData_has_layer(&dm->polyData, CD_NORMAL) == false)); */
-
- if ((dm->type == DM_TYPE_CDDM) &&
- ((dm->dirty & DM_DIRTY_NORMALS) || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false))
- {
- /* if normals are dirty we want to calculate vertex normals too */
- CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true);
- }
-}
-
-/**
- * new value for useDeform -1 (hack for the gameengine):
- *
- * - apply only the modifier stack of the object, skipping the virtual modifiers,
- * - don't apply the key
- * - apply deform modifiers and input vertexco
- */
static void mesh_calc_modifiers(
- Scene *scene, Object *ob, float (*inputVertexCos)[3],
- const bool useRenderParams, int useDeform,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (*inputVertexCos)[3],
+ int useDeform,
const bool need_mapping, CustomDataMask dataMask,
const int index, const bool useCache, const bool build_shapekey_layers,
- const bool allow_gpu,
/* return args */
- DerivedMesh **r_deform, DerivedMesh **r_final)
+ Mesh **r_deform, Mesh **r_final)
{
- Mesh *me = ob->data;
ModifierData *firstmd, *md, *previewmd = NULL;
CDMaskLink *datamasks, *curr;
/* XXX Always copying POLYINDEX, else tessellated data are no more valid! */
CustomDataMask mask, nextmask, previewmask = 0, append_mask = CD_MASK_ORIGINDEX;
float (*deformedVerts)[3] = NULL;
- DerivedMesh *dm = NULL, *orcodm, *clothorcodm, *finaldm;
- int numVerts = me->totvert;
+ int numVerts = ((Mesh *)ob->data)->totvert;
+ const bool useRenderParams = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int required_mode = useRenderParams ? eModifierMode_Render : eModifierMode_Realtime;
bool isPrevDeform = false;
- const bool skipVirtualArmature = (useDeform < 0);
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
const bool has_multires = (mmd && mmd->sculptlvl != 0);
bool multires_applied = false;
const bool sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt && !useRenderParams;
const bool sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm) && !useRenderParams;
- const int draw_flag = dm_drawflag_calc(scene->toolsettings, me);
/* Generic preview only in object mode! */
const bool do_mod_mcol = (ob->mode == OB_MODE_OBJECT);
-#if 0 /* XXX Will re-enable this when we have global mod stack options. */
- const bool do_final_wmcol = (scene->toolsettings->weights_preview == WP_WPREVIEW_FINAL) && do_wmcol;
-#endif
- const bool do_final_wmcol = false;
- const bool do_init_wmcol = ((dataMask & CD_MASK_PREVIEW_MLOOPCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT) && !do_final_wmcol);
- /* XXX Same as above... For now, only weights preview in WPaint mode. */
- const bool do_mod_wmcol = do_init_wmcol;
-
- const bool do_loop_normals = (me->flag & ME_AUTOSMOOTH) != 0;
- const float loop_normals_split_angle = me->smoothresh;
+ const bool do_loop_normals = (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) != 0;
VirtualModifierData virtualModifierData;
ModifierApplyFlag app_flags = useRenderParams ? MOD_APPLY_RENDER : 0;
ModifierApplyFlag deform_app_flags = app_flags;
+ BLI_assert((((Mesh *)ob->data)->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
if (useCache)
app_flags |= MOD_APPLY_USECACHE;
- if (allow_gpu)
- app_flags |= MOD_APPLY_ALLOW_GPU;
if (useDeform)
deform_app_flags |= MOD_APPLY_USECACHE;
- if (!skipVirtualArmature) {
- firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
- }
- else {
- /* game engine exception */
- firstmd = ob->modifiers.first;
- if (firstmd && firstmd->type == eModifierType_Armature)
- firstmd = firstmd->next;
- }
+ /* TODO(sybren): do we really need three context objects? Or do we modify
+ * them on the fly to change the flags where needed? */
+ const ModifierEvalContext mectx_deform = {depsgraph, ob, deform_app_flags};
+ const ModifierEvalContext mectx_apply = {depsgraph, ob, app_flags};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO};
- md = firstmd;
+ md = firstmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
modifiers_clearErrors(ob);
- if (do_mod_wmcol || do_mod_mcol) {
+ if (do_mod_mcol) {
/* Find the last active modifier generating a preview, or NULL if none. */
/* XXX Currently, DPaint modifier just ignores this.
* Needs a stupid hack...
* The whole "modifier preview" thing has to be (re?)designed, anyway! */
previewmd = modifiers_getLastPreview(scene, md, required_mode);
-
- /* even if the modifier doesn't need the data, to make a preview it may */
- if (previewmd) {
- if (do_mod_wmcol) {
- previewmask = CD_MASK_MDEFORMVERT;
- }
- }
}
datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, previewmask);
@@ -1849,8 +1224,6 @@ static void mesh_calc_modifiers(
for (; md; md = md->next, curr = curr->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!modifier_isEnabled(scene, md, required_mode)) {
continue;
}
@@ -1861,9 +1234,9 @@ static void mesh_calc_modifiers(
if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) {
if (!deformedVerts)
- deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts);
- modwrap_deformVerts(md, ob, NULL, deformedVerts, numVerts, deform_app_flags);
+ modwrap_deformVerts(md, &mectx_deform, NULL, deformedVerts, numVerts);
}
else {
break;
@@ -1879,13 +1252,16 @@ static void mesh_calc_modifiers(
* coordinates (vpaint, etc.)
*/
if (r_deform) {
- *r_deform = CDDM_from_mesh(me);
+ *r_deform = BKE_mesh_copy_for_eval(ob->data, true);
- if (build_shapekey_layers)
- add_shapekey_layers(dm, me, ob);
+ /* XXX: Is build_shapekey_layers ever even true? This should have crashed long ago... */
+ BLI_assert(!build_shapekey_layers);
+ if (build_shapekey_layers) {
+ add_shapekey_layers(*r_deform, ob->data, ob);
+ }
if (deformedVerts) {
- CDDM_apply_vert_coords(*r_deform, deformedVerts);
+ BKE_mesh_apply_vert_coords(*r_deform, deformedVerts);
}
}
}
@@ -1894,22 +1270,20 @@ static void mesh_calc_modifiers(
if (inputVertexCos)
deformedVerts = inputVertexCos;
else
- deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts);
}
/* Now apply all remaining modifiers. If useDeform is off then skip
* OnlyDeform ones.
*/
- dm = NULL;
- orcodm = NULL;
- clothorcodm = NULL;
+ Mesh *me = NULL;
+ Mesh *me_orco = NULL;
+ Mesh *me_orco_cloth = NULL;
for (; md; md = md->next, curr = curr->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!modifier_isEnabled(scene, md, required_mode)) {
continue;
}
@@ -1918,7 +1292,7 @@ static void mesh_calc_modifiers(
continue;
}
- if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+ if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && me) {
modifier_setError(md, "Modifier requires original data, bad stack position");
continue;
}
@@ -1969,29 +1343,27 @@ static void mesh_calc_modifiers(
else
mask = 0;
- if (dm && (mask & CD_MASK_ORCO))
- add_orco_dm(ob, NULL, dm, orcodm, CD_ORCO);
+ if (me && (mask & CD_MASK_ORCO)) {
+ add_orco_mesh(ob, NULL, me, me_orco, CD_ORCO);
+ }
/* How to apply modifier depends on (a) what we already have as
- * a result of previous modifiers (could be a DerivedMesh or just
+ * a result of previous modifiers (could be a Mesh or just
* deformed vertices) and (b) what type the modifier is.
*/
if (mti->type == eModifierTypeType_OnlyDeform) {
/* No existing verts to deform, need to build them. */
if (!deformedVerts) {
- if (dm) {
- /* Deforming a derived mesh, read the vertex locations
+ if (me) {
+ /* Deforming a mesh, read the vertex locations
* out of the mesh and deform them. Once done with this
* run of deformers verts will be written back.
*/
- numVerts = dm->getNumVerts(dm);
- deformedVerts =
- MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv");
- dm->getVertCos(dm, deformedVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
}
else {
- deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(ob->data, &numVerts);
}
}
@@ -1999,46 +1371,38 @@ static void mesh_calc_modifiers(
* to avoid giving bogus normals to the next modifier see: [#23673] */
if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
/* XXX, this covers bug #23673, but we may need normal calc for other types */
- if (dm && dm->type == DM_TYPE_CDDM) {
- CDDM_apply_vert_coords(dm, deformedVerts);
+ if (me) {
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
}
- modwrap_deformVerts(md, ob, dm, deformedVerts, numVerts, deform_app_flags);
+ modwrap_deformVerts(md, &mectx_deform, me, deformedVerts, numVerts);
}
else {
- DerivedMesh *ndm;
-
/* determine which data layers are needed by following modifiers */
if (curr->next)
nextmask = curr->next->mask;
else
nextmask = dataMask;
- /* apply vertex coordinates or build a DerivedMesh as necessary */
- if (dm) {
+ /* apply vertex coordinates or build a Mesh as necessary */
+ if (me) {
if (deformedVerts) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
-
- CDDM_apply_vert_coords(dm, deformedVerts);
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
}
else {
- dm = CDDM_from_mesh(me);
- ASSERT_IS_VALID_DM(dm);
+ me = BKE_mesh_copy_for_eval(ob->data, true);
+ ASSERT_IS_VALID_MESH(me);
- if (build_shapekey_layers)
- add_shapekey_layers(dm, me, ob);
+ if (build_shapekey_layers) {
+ add_shapekey_layers(me, ob->data, ob);
+ }
if (deformedVerts) {
- CDDM_apply_vert_coords(dm, deformedVerts);
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
- if (do_init_wmcol)
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
-
/* Constructive modifiers need to have an origindex
* otherwise they wont have anywhere to copy the data from.
*
@@ -2048,91 +1412,101 @@ static void mesh_calc_modifiers(
*/
if (need_mapping || (nextmask & CD_MASK_ORIGINDEX)) {
/* calc */
- DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
- DM_add_poly_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+ CustomData_add_layer(&me->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totvert);
+ CustomData_add_layer(&me->edata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totedge);
+ CustomData_add_layer(&me->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, me->totpoly);
/* Not worth parallelizing this, gives less than 0.1% overall speedup in best of best cases... */
- range_vn_i(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
- range_vn_i(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
- range_vn_i(DM_get_poly_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0);
+ range_vn_i(CustomData_get_layer(&me->vdata, CD_ORIGINDEX), me->totvert, 0);
+ range_vn_i(CustomData_get_layer(&me->edata, CD_ORIGINDEX), me->totedge, 0);
+ range_vn_i(CustomData_get_layer(&me->pdata, CD_ORIGINDEX), me->totpoly, 0);
}
}
- /* set the DerivedMesh to only copy needed data */
+ /* set the Mesh to only copy needed data */
mask = curr->mask;
/* needMapping check here fixes bug [#28112], otherwise it's
* possible that it won't be copied */
mask |= append_mask;
- DM_set_only_copy(dm, mask | (need_mapping ? CD_MASK_ORIGINDEX : 0));
+ mesh_set_only_copy(me, mask | (need_mapping ? CD_MASK_ORIGINDEX : 0));
/* add cloth rest shape key if needed */
if (mask & CD_MASK_CLOTH_ORCO)
- add_orco_dm(ob, NULL, dm, clothorcodm, CD_CLOTH_ORCO);
+ add_orco_mesh(ob, NULL, me, me_orco, CD_CLOTH_ORCO);
/* add an origspace layer if needed */
if ((curr->mask) & CD_MASK_ORIGSPACE_MLOOP) {
- if (!CustomData_has_layer(&dm->loopData, CD_ORIGSPACE_MLOOP)) {
- DM_add_loop_layer(dm, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL);
- DM_init_origspace(dm);
+ if (!CustomData_has_layer(&me->ldata, CD_ORIGSPACE_MLOOP)) {
+ CustomData_add_layer(&me->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, me->totloop);
+ mesh_init_origspace(me);
}
}
- ndm = modwrap_applyModifier(md, ob, dm, app_flags);
- ASSERT_IS_VALID_DM(ndm);
-
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (dm && dm != ndm) dm->release(dm);
+ Mesh *me_next = modwrap_applyModifier(md, &mectx_apply, me);
+ ASSERT_IS_VALID_MESH(me_next);
- dm = ndm;
+ if (me_next) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (me && me != me_next) {
+ BLI_assert(me != ob->data);
+ BKE_id_free(NULL, me);
+ }
+ me = me_next;
if (deformedVerts) {
- if (deformedVerts != inputVertexCos)
+ if (deformedVerts != inputVertexCos) {
MEM_freeN(deformedVerts);
-
+ }
deformedVerts = NULL;
}
}
- /* create an orco derivedmesh in parallel */
+ /* create an orco mesh in parallel */
if (nextmask & CD_MASK_ORCO) {
- if (!orcodm)
- orcodm = create_orco_dm(ob, me, NULL, CD_ORCO);
+ if (!me_orco) {
+ me_orco = create_orco_mesh(ob, ob->data, NULL, CD_ORCO);
+ }
nextmask &= ~CD_MASK_ORCO;
- DM_set_only_copy(orcodm, nextmask | CD_MASK_ORIGINDEX |
+ mesh_set_only_copy(me_orco, nextmask | CD_MASK_ORIGINDEX |
(mti->requiredDataMask ?
mti->requiredDataMask(ob, md) : 0));
- ndm = modwrap_applyModifier(md, ob, orcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO);
- ASSERT_IS_VALID_DM(ndm);
+ me_next = modwrap_applyModifier(md, &mectx_orco, me_orco);
+ ASSERT_IS_VALID_MESH(me_next);
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (orcodm && orcodm != ndm) orcodm->release(orcodm);
- orcodm = ndm;
+ if (me_next) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (me_orco && me_orco != me_next) {
+ BLI_assert(me_orco != ob->data);
+ BKE_id_free(NULL, me_orco);
+ }
+
+ me_orco = me_next;
}
}
- /* create cloth orco derivedmesh in parallel */
+ /* create cloth orco mesh in parallel */
if (nextmask & CD_MASK_CLOTH_ORCO) {
- if (!clothorcodm)
- clothorcodm = create_orco_dm(ob, me, NULL, CD_CLOTH_ORCO);
+ if (!me_orco_cloth) {
+ me_orco_cloth = create_orco_mesh(ob, ob->data, NULL, CD_CLOTH_ORCO);
+ }
nextmask &= ~CD_MASK_CLOTH_ORCO;
- DM_set_only_copy(clothorcodm, nextmask | CD_MASK_ORIGINDEX);
+ mesh_set_only_copy(me_orco_cloth, nextmask | CD_MASK_ORIGINDEX);
- ndm = modwrap_applyModifier(md, ob, clothorcodm, (app_flags & ~MOD_APPLY_USECACHE) | MOD_APPLY_ORCO);
- ASSERT_IS_VALID_DM(ndm);
+ me_next = modwrap_applyModifier(md, &mectx_orco, me_orco_cloth);
+ ASSERT_IS_VALID_DM(me_next);
- if (ndm) {
- /* if the modifier returned a new dm, release the old one */
- if (clothorcodm && clothorcodm != ndm) {
- clothorcodm->release(clothorcodm);
+ if (me_next) {
+ /* if the modifier returned a new mesh, release the old one */
+ if (me_orco_cloth && me_orco_cloth != me_next) {
+ BLI_assert(me_orco != ob->data);
+ BKE_id_free(NULL, me_orco_cloth);
}
- clothorcodm = ndm;
+
+ me_orco_cloth = me_next;
}
}
@@ -2140,13 +1514,8 @@ static void mesh_calc_modifiers(
/* XXX Temp and hackish solution! */
if (md->type == eModifierType_DynamicPaint)
append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
- /* In case of active preview modifier, make sure preview mask remains for following modifiers. */
- else if ((md == previewmd) && (do_mod_wmcol)) {
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
- append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
- }
- dm->deformedOnly = false;
+ me->runtime.deformed_only = false;
}
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
@@ -2163,65 +1532,47 @@ static void mesh_calc_modifiers(
for (md = firstmd; md; md = md->next)
modifier_freeTemporaryData(md);
- /* Yay, we are done. If we have a DerivedMesh and deformed vertices
- * need to apply these back onto the DerivedMesh. If we have no
- * DerivedMesh then we need to build one.
+ /* Yay, we are done. If we have a Mesh and deformed vertices
+ * need to apply these back onto the Mesh. If we have no
+ * Mesh then we need to build one.
*/
- if (dm && deformedVerts) {
- finaldm = CDDM_copy(dm);
-
- dm->release(dm);
-
- CDDM_apply_vert_coords(finaldm, deformedVerts);
-
-#if 0 /* For later nice mod preview! */
- /* In case we need modified weights in CD_PREVIEW_MCOL, we have to re-compute it. */
- if (do_final_wmcol)
- DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
-#endif
- }
- else if (dm) {
- finaldm = dm;
+ if (me) {
+ *r_final = me;
-#if 0 /* For later nice mod preview! */
- /* In case we need modified weights in CD_PREVIEW_MCOL, we have to re-compute it. */
- if (do_final_wmcol)
- DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
-#endif
+ if (deformedVerts) {
+ BKE_mesh_apply_vert_coords(*r_final, deformedVerts);
+ }
}
else {
- finaldm = CDDM_from_mesh(me);
+ *r_final = BKE_mesh_copy_for_eval(ob->data, true);
if (build_shapekey_layers) {
- add_shapekey_layers(finaldm, me, ob);
+ add_shapekey_layers(*r_final, ob->data, ob);
}
if (deformedVerts) {
- CDDM_apply_vert_coords(finaldm, deformedVerts);
+ BKE_mesh_apply_vert_coords(*r_final, deformedVerts);
}
-
- /* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_wmcol)
- DM_update_weight_mcol(ob, finaldm, draw_flag, NULL, 0, NULL);
}
/* add an orco layer if needed */
if (dataMask & CD_MASK_ORCO) {
- add_orco_dm(ob, NULL, finaldm, orcodm, CD_ORCO);
+ add_orco_mesh(ob, NULL, *r_final, me_orco, CD_ORCO);
if (r_deform && *r_deform)
- add_orco_dm(ob, NULL, *r_deform, NULL, CD_ORCO);
+ add_orco_mesh(ob, NULL, *r_deform, NULL, CD_ORCO);
}
if (do_loop_normals) {
/* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */
- DM_calc_loop_normals(finaldm, do_loop_normals, loop_normals_split_angle);
+ BKE_mesh_calc_normals_split(*r_final);
+ BKE_mesh_tessface_clear(*r_final);
}
if (sculpt_dyntopo == false) {
/* watch this! after 2.75a we move to from tessface to looptri (by default) */
if (dataMask & CD_MASK_MFACE) {
- DM_ensure_tessface(finaldm);
+ BKE_mesh_tessface_ensure(*r_final);
}
/* without this, drawing ngon tri's faces will show ugly tessellated face
@@ -2234,36 +1585,22 @@ static void mesh_calc_modifiers(
* If using loop normals, poly nors have already been computed.
*/
if (!do_loop_normals) {
- dm_ensure_display_normals(finaldm);
+ BKE_mesh_ensure_normals_for_display(*r_final);
}
}
/* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them,
* as they are used by display code when available (i.e. even if autosmooth is disabled). */
- if (!do_loop_normals && CustomData_has_layer(&finaldm->loopData, CD_NORMAL)) {
- CustomData_free_layers(&finaldm->loopData, CD_NORMAL, finaldm->numLoopData);
+ if (!do_loop_normals && CustomData_has_layer(&(*r_final)->ldata, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_final)->ldata, CD_NORMAL, (*r_final)->totloop);
}
-#ifdef WITH_GAMEENGINE
- /* NavMesh - this is a hack but saves having a NavMesh modifier */
- if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) {
- DerivedMesh *tdm;
- tdm = navmesh_dm_createNavMeshForVisualization(finaldm);
- if (finaldm != tdm) {
- finaldm->release(finaldm);
- finaldm = tdm;
- }
-
- DM_ensure_tessface(finaldm);
+ if (me_orco) {
+ BKE_id_free(NULL, me_orco);
+ }
+ if (me_orco_cloth) {
+ BKE_id_free(NULL, me_orco_cloth);
}
-#endif /* WITH_GAMEENGINE */
-
- *r_final = finaldm;
-
- if (orcodm)
- orcodm->release(orcodm);
- if (clothorcodm)
- clothorcodm->release(clothorcodm);
if (deformedVerts && deformedVerts != inputVertexCos)
MEM_freeN(deformedVerts);
@@ -2271,6 +1608,30 @@ static void mesh_calc_modifiers(
BLI_linklist_free((LinkNode *)datamasks, NULL);
}
+static void mesh_calc_modifiers_dm(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (*inputVertexCos)[3],
+ int useDeform,
+ const bool need_mapping, CustomDataMask dataMask,
+ const int index, const bool useCache, const bool build_shapekey_layers,
+ /* return args */
+ DerivedMesh **r_deformdm, DerivedMesh **r_finaldm)
+{
+ Mesh *deform_mesh = NULL, *final_mesh = NULL;
+
+ mesh_calc_modifiers(
+ depsgraph, scene, ob, inputVertexCos, useDeform,
+ need_mapping, dataMask, index, useCache, build_shapekey_layers,
+ (r_deformdm ? &deform_mesh : NULL), &final_mesh);
+
+ if (deform_mesh) {
+ *r_deformdm = CDDM_from_mesh_ex(deform_mesh, CD_DUPLICATE, CD_MASK_MESH);
+ BKE_id_free(NULL, deform_mesh);
+ }
+
+ *r_finaldm = CDDM_from_mesh_ex(final_mesh, CD_DUPLICATE, CD_MASK_MESH);
+ BKE_id_free(NULL, final_mesh);
+}
+
float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3]
{
BMIter iter;
@@ -2289,7 +1650,7 @@ float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *r_numVerts))[3]
return cos;
}
-bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
+bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, bool has_prev_mesh)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
@@ -2298,7 +1659,7 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *
return false;
}
- if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+ if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && has_prev_mesh) {
modifier_setError(md, "Modifier requires original data, bad stack position");
return false;
}
@@ -2307,68 +1668,56 @@ bool editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *
}
static void editbmesh_calc_modifiers(
- Scene *scene, Object *ob, BMEditMesh *em,
- CustomDataMask dataMask,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ BMEditMesh *em, CustomDataMask dataMask,
/* return args */
- DerivedMesh **r_cage, DerivedMesh **r_final)
+ Mesh **r_cage, Mesh **r_final)
{
- ModifierData *md, *previewmd = NULL;
+ ModifierData *md;
float (*deformedVerts)[3] = NULL;
- CustomDataMask mask = 0, previewmask = 0, append_mask = 0;
- DerivedMesh *dm = NULL, *orcodm = NULL;
+ CustomDataMask mask = 0, append_mask = 0;
int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
CDMaskLink *datamasks, *curr;
const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
- int draw_flag = dm_drawflag_calc(scene->toolsettings, ob->data);
-
- // const bool do_mod_mcol = true; // (ob->mode == OB_MODE_OBJECT);
-#if 0 /* XXX Will re-enable this when we have global mod stack options. */
- const bool do_final_wmcol = (scene->toolsettings->weights_preview == WP_WPREVIEW_FINAL) && do_wmcol;
-#endif
- const bool do_final_wmcol = false;
- const bool do_init_wmcol = ((((Mesh *)ob->data)->drawflag & ME_DRAWEIGHT) && !do_final_wmcol);
-
- const bool do_init_statvis = ((((Mesh *)ob->data)->drawflag & ME_DRAW_STATVIS) && !do_init_wmcol);
- const bool do_mod_wmcol = do_init_wmcol;
+ const bool do_init_statvis = false; /* FIXME: use V3D_OVERLAY_EDIT_STATVIS. */
VirtualModifierData virtualModifierData;
+ /* TODO(sybren): do we really need multiple objects, or shall we change the flags where needed? */
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
+ const ModifierEvalContext mectx_orco = {depsgraph, ob, MOD_APPLY_ORCO};
+ const ModifierEvalContext mectx_cache = {depsgraph, ob, MOD_APPLY_USECACHE};
+
const bool do_loop_normals = (((Mesh *)(ob->data))->flag & ME_AUTOSMOOTH) != 0;
- const float loop_normals_split_angle = ((Mesh *)(ob->data))->smoothresh;
modifiers_clearErrors(ob);
if (r_cage && cageIndex == -1) {
- *r_cage = getEditDerivedBMesh(em, ob, dataMask, NULL);
+ *r_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, dataMask, NULL);
}
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* copied from mesh_calc_modifiers */
- if (do_mod_wmcol) {
- previewmd = modifiers_getLastPreview(scene, md, required_mode);
- /* even if the modifier doesn't need the data, to make a preview it may */
- if (previewmd) {
- previewmask = CD_MASK_MDEFORMVERT;
- }
- }
-
- datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, previewmd, previewmask);
+ datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode, NULL, 0);
curr = datamasks;
+
+ Mesh *me = NULL;
+ Mesh *me_orco = NULL;
+
for (i = 0; md; i++, md = md->next, curr = curr->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
- if (!editbmesh_modifier_is_enabled(scene, md, dm)) {
+ if (!editbmesh_modifier_is_enabled(scene, md, me != NULL)) {
continue;
}
/* add an orco layer if needed by this modifier */
- if (dm && mti->requiredDataMask) {
+ if (me && mti->requiredDataMask) {
mask = mti->requiredDataMask(ob, md);
- if (mask & CD_MASK_ORCO)
- add_orco_dm(ob, em, dm, orcodm, CD_ORCO);
+ if (mask & CD_MASK_ORCO) {
+ add_orco_mesh(ob, em, me, me_orco, CD_ORCO);
+ }
}
/* How to apply modifier depends on (a) what we already have as
@@ -2379,15 +1728,12 @@ static void editbmesh_calc_modifiers(
if (mti->type == eModifierTypeType_OnlyDeform) {
/* No existing verts to deform, need to build them. */
if (!deformedVerts) {
- if (dm) {
+ if (me) {
/* Deforming a derived mesh, read the vertex locations
* out of the mesh and deform them. Once done with this
* run of deformers verts will be written back.
*/
- numVerts = dm->getNumVerts(dm);
- deformedVerts =
- MEM_malloc_arrayN(numVerts, sizeof(*deformedVerts), "dfmv");
- dm->getVertCos(dm, deformedVerts);
+ deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
}
else {
deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
@@ -2395,64 +1741,58 @@ static void editbmesh_calc_modifiers(
}
if (mti->deformVertsEM)
- modwrap_deformVertsEM(md, ob, em, dm, deformedVerts, numVerts);
+ modwrap_deformVertsEM(md, &mectx, em, me, deformedVerts, numVerts);
else
- modwrap_deformVerts(md, ob, dm, deformedVerts, numVerts, 0);
+ modwrap_deformVerts(md, &mectx, me, deformedVerts, numVerts);
}
else {
- DerivedMesh *ndm;
+ Mesh *me_next;
/* apply vertex coordinates or build a DerivedMesh as necessary */
- if (dm) {
+ if (me) {
if (deformedVerts) {
- DerivedMesh *tdm = CDDM_copy(dm);
- if (!(r_cage && dm == *r_cage)) {
- dm->release(dm);
- }
- dm = tdm;
+ Mesh *me_temp = BKE_mesh_copy_for_eval(me, false);
- CDDM_apply_vert_coords(dm, deformedVerts);
+ if (!(r_cage && me == *r_cage)) {
+ BKE_id_free(NULL, me);
+ }
+ me = me_temp;
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
- else if (r_cage && dm == *r_cage) {
- /* dm may be changed by this modifier, so we need to copy it */
- dm = CDDM_copy(dm);
+ else if (r_cage && me == *r_cage) {
+ /* 'me' may be changed by this modifier, so we need to copy it. */
+ me = BKE_mesh_copy_for_eval(me, false);
}
}
else {
- dm = CDDM_from_editbmesh(em, false, false);
- ASSERT_IS_VALID_DM(dm);
+ me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0);
+ ASSERT_IS_VALID_MESH(me);
if (deformedVerts) {
- CDDM_apply_vert_coords(dm, deformedVerts);
- }
-
- if (do_init_wmcol) {
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
+ BKE_mesh_apply_vert_coords(me, deformedVerts);
}
}
/* create an orco derivedmesh in parallel */
mask = curr->mask;
if (mask & CD_MASK_ORCO) {
- if (!orcodm)
- orcodm = create_orco_dm(ob, ob->data, em, CD_ORCO);
+ if (!me_orco) {
+ me_orco = create_orco_mesh(ob, ob->data, em, CD_ORCO);
+ }
mask &= ~CD_MASK_ORCO;
- DM_set_only_copy(orcodm, mask | CD_MASK_ORIGINDEX);
+ mesh_set_only_copy(me_orco, mask | CD_MASK_ORIGINDEX);
- if (mti->applyModifierEM) {
- ndm = modwrap_applyModifierEM(md, ob, em, orcodm, MOD_APPLY_ORCO);
- }
- else {
- ndm = modwrap_applyModifier(md, ob, orcodm, MOD_APPLY_ORCO);
- }
- ASSERT_IS_VALID_DM(ndm);
+ me_next = modwrap_applyModifier(md, &mectx_orco, me_orco);
+ ASSERT_IS_VALID_MESH(me_next);
- if (ndm) {
+ if (me_next) {
/* if the modifier returned a new dm, release the old one */
- if (orcodm && orcodm != ndm) orcodm->release(orcodm);
- orcodm = ndm;
+ if (me_orco && me_orco != me_next) {
+ BKE_id_free(NULL, me_orco);
+ }
+ me_orco = me_next;
}
}
@@ -2460,53 +1800,48 @@ static void editbmesh_calc_modifiers(
mask |= append_mask;
mask = curr->mask; /* CD_MASK_ORCO may have been cleared above */
- DM_set_only_copy(dm, mask | CD_MASK_ORIGINDEX);
+ mesh_set_only_copy(me, mask | CD_MASK_ORIGINDEX);
if (mask & CD_MASK_ORIGSPACE_MLOOP) {
- if (!CustomData_has_layer(&dm->loopData, CD_ORIGSPACE_MLOOP)) {
- DM_add_loop_layer(dm, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL);
- DM_init_origspace(dm);
+ if (!CustomData_has_layer(&me->ldata, CD_ORIGSPACE_MLOOP)) {
+ CustomData_add_layer(&me->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, NULL, me->totloop);
+ mesh_init_origspace(me);
}
}
- if (mti->applyModifierEM)
- ndm = modwrap_applyModifierEM(md, ob, em, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU);
- else
- ndm = modwrap_applyModifier(md, ob, dm, MOD_APPLY_USECACHE | MOD_APPLY_ALLOW_GPU);
- ASSERT_IS_VALID_DM(ndm);
-
- if (ndm) {
- if (dm && dm != ndm)
- dm->release(dm);
+ me_next = modwrap_applyModifier(md, &mectx_cache, me);
+ ASSERT_IS_VALID_MESH(me_next);
- dm = ndm;
+ if (me_next) {
+ if (me && me != me_next) {
+ BKE_id_free(NULL, me);
+ }
+ me = me_next;
if (deformedVerts) {
MEM_freeN(deformedVerts);
deformedVerts = NULL;
}
}
-
- dm->deformedOnly = false;
- }
-
- /* In case of active preview modifier, make sure preview mask remains for following modifiers. */
- if ((md == previewmd) && (do_mod_wmcol)) {
- DM_update_weight_mcol(ob, dm, draw_flag, NULL, 0, NULL);
- append_mask |= CD_MASK_PREVIEW_MLOOPCOL;
+ me->runtime.deformed_only = false;
}
if (r_cage && i == cageIndex) {
- if (dm && deformedVerts) {
- *r_cage = CDDM_copy(dm);
- CDDM_apply_vert_coords(*r_cage, deformedVerts);
+ if (me && deformedVerts) {
+ *r_cage = BKE_mesh_copy_for_eval(me, false);
+ BKE_mesh_apply_vert_coords(*r_cage, deformedVerts);
}
- else if (dm) {
- *r_cage = dm;
+ else if (me) {
+ *r_cage = me;
}
else {
- *r_cage = getEditDerivedBMesh(
- em, ob, mask,
+ Mesh *me_orig = ob->data;
+ if (me_orig->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ BKE_mesh_runtime_ensure_edit_data(me_orig);
+ me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformedVerts);
+ }
+ *r_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ em, mask,
deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
}
}
@@ -2518,45 +1853,44 @@ static void editbmesh_calc_modifiers(
* to apply these back onto the DerivedMesh. If we have no DerivedMesh
* then we need to build one.
*/
- if (dm && deformedVerts) {
- *r_final = CDDM_copy(dm);
+ if (me && deformedVerts) {
+ *r_final = BKE_mesh_copy_for_eval(me, false);
- if (!(r_cage && dm == *r_cage)) {
- dm->release(dm);
+ if (!(r_cage && me == *r_cage)) {
+ BKE_id_free(NULL, me);
}
-
- CDDM_apply_vert_coords(*r_final, deformedVerts);
+ BKE_mesh_apply_vert_coords(*r_final, deformedVerts);
}
- else if (dm) {
- *r_final = dm;
+ else if (me) {
+ *r_final = me;
}
else if (!deformedVerts && r_cage && *r_cage) {
/* cage should already have up to date normals */
*r_final = *r_cage;
/* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_wmcol)
- DM_update_weight_mcol(ob, *r_final, draw_flag, NULL, 0, NULL);
- if (do_init_statvis)
- DM_update_statvis_color(scene, ob, *r_final);
+ if (do_init_statvis) {
+ editmesh_update_statvis_color(scene, ob);
+ }
}
else {
/* this is just a copy of the editmesh, no need to calc normals */
- *r_final = getEditDerivedBMesh(em, ob, dataMask, deformedVerts);
+ *r_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, dataMask, deformedVerts);
deformedVerts = NULL;
/* In this case, we should never have weight-modifying modifiers in stack... */
- if (do_init_wmcol)
- DM_update_weight_mcol(ob, *r_final, draw_flag, NULL, 0, NULL);
- if (do_init_statvis)
- DM_update_statvis_color(scene, ob, *r_final);
+ if (do_init_statvis) {
+ editmesh_update_statvis_color(scene, ob);
+ }
}
if (do_loop_normals) {
/* Compute loop normals */
- DM_calc_loop_normals(*r_final, do_loop_normals, loop_normals_split_angle);
+ BKE_mesh_calc_normals_split(*r_final);
+ BKE_mesh_tessface_clear(*r_final);
if (r_cage && *r_cage && (*r_cage != *r_final)) {
- DM_calc_loop_normals(*r_cage, do_loop_normals, loop_normals_split_angle);
+ BKE_mesh_calc_normals_split(*r_cage);
+ BKE_mesh_tessface_clear(*r_cage);
}
}
@@ -2565,13 +1899,13 @@ static void editbmesh_calc_modifiers(
* check if the derived meshes are DM_TYPE_EDITBMESH before calling, this isn't essential
* but quiets annoying error messages since tessfaces wont be created. */
if (dataMask & CD_MASK_MFACE) {
- if ((*r_final)->type != DM_TYPE_EDITBMESH) {
- DM_ensure_tessface(*r_final);
+ if ((*r_final)->edit_btmesh == NULL) {
+ BKE_mesh_tessface_ensure(*r_final);
}
if (r_cage && *r_cage) {
- if ((*r_cage)->type != DM_TYPE_EDITBMESH) {
+ if ((*r_cage)->edit_btmesh == NULL) {
if (*r_cage != *r_final) {
- DM_ensure_tessface(*r_cage);
+ BKE_mesh_tessface_ensure(*r_cage);
}
}
}
@@ -2580,63 +1914,84 @@ static void editbmesh_calc_modifiers(
/* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */
if (!do_loop_normals) {
- dm_ensure_display_normals(*r_final);
+ BKE_mesh_ensure_normals_for_display(*r_final);
/* Some modifiers, like datatransfer, may generate those data, we do not want to keep them,
* as they are used by display code when available (i.e. even if autosmooth is disabled). */
- if (CustomData_has_layer(&(*r_final)->loopData, CD_NORMAL)) {
- CustomData_free_layers(&(*r_final)->loopData, CD_NORMAL, (*r_final)->numLoopData);
+ if (CustomData_has_layer(&(*r_final)->ldata, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_final)->ldata, CD_NORMAL, (*r_final)->totloop);
}
- if (r_cage && CustomData_has_layer(&(*r_cage)->loopData, CD_NORMAL)) {
- CustomData_free_layers(&(*r_cage)->loopData, CD_NORMAL, (*r_cage)->numLoopData);
+ if (r_cage && CustomData_has_layer(&(*r_cage)->ldata, CD_NORMAL)) {
+ CustomData_free_layers(&(*r_cage)->ldata, CD_NORMAL, (*r_cage)->totloop);
}
}
/* add an orco layer if needed */
if (dataMask & CD_MASK_ORCO)
- add_orco_dm(ob, em, *r_final, orcodm, CD_ORCO);
+ add_orco_mesh(ob, em, *r_final, me_orco, CD_ORCO);
- if (orcodm)
- orcodm->release(orcodm);
+ if (me_orco) {
+ BKE_id_free(NULL, me_orco);
+ }
- if (deformedVerts)
+ if (deformedVerts) {
MEM_freeN(deformedVerts);
+ }
}
-#ifdef WITH_OPENSUBDIV
-/* The idea is to skip CPU-side ORCO calculation when
- * we'll be using GPU backend of OpenSubdiv. This is so
- * playback performance is kept as high as possible.
- */
-static bool calc_modifiers_skip_orco(Scene *scene,
- Object *ob,
- bool use_render_params)
+static void mesh_finalize_eval(Object *object)
{
- ModifierData *last_md = ob->modifiers.last;
- const int required_mode = use_render_params ? eModifierMode_Render : eModifierMode_Realtime;
- if (last_md != NULL &&
- last_md->type == eModifierType_Subsurf &&
- modifier_isEnabled(scene, last_md, required_mode))
- {
- if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) {
- return false;
- }
- else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) {
- return false;
- }
- else if ((DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CPU) != 0) {
- return false;
- }
- SubsurfModifierData *smd = (SubsurfModifierData *)last_md;
- /* TODO(sergey): Deduplicate this with checks from subsurf_ccg.c. */
- return smd->use_opensubdiv != 0;
+ Mesh *mesh = (Mesh *)object->data;
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ /* Special Tweaks for cases when evaluated mesh came from
+ * BKE_mesh_new_nomain_from_template().
+ */
+ BLI_strncpy(mesh_eval->id.name, mesh->id.name, sizeof(mesh_eval->id.name));
+ if (mesh_eval->mat != NULL) {
+ MEM_freeN(mesh_eval->mat);
+ }
+ /* Set flag which makes it easier to see what's going on in a debugger. */
+ mesh_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT;
+ mesh_eval->mat = MEM_dupallocN(mesh->mat);
+ mesh_eval->totcol = mesh->totcol;
+ /* Make evaluated mesh to share same edit mesh pointer as original
+ * and copied meshes.
+ */
+ mesh_eval->edit_btmesh = mesh->edit_btmesh;
+ /* Copy autosmooth settings from original mesh.
+ * This is not done by BKE_mesh_new_nomain_from_template(), so need to take
+ * extra care here.
+ */
+ mesh_eval->flag |= (mesh->flag & ME_AUTOSMOOTH);
+ mesh_eval->smoothresh = mesh->smoothresh;
+ /* Replace evaluated object's data with fully evaluated mesh. */
+ /* TODO(sergey): There was statement done by Sybren and Mai that this
+ * caused modifiers to be applied twice. which is weirtd and shouldn't
+ * really happen. But since there is no reference to the report, can not
+ * do much about this.
+ */
+
+ /* Object is sometimes not evaluated!
+ * TODO(sergey): BAD TEMPORARY HACK FOR UNTIL WE ARE SMARTER */
+ if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ object->data = mesh_eval;
+ }
+ else {
+ /* evaluated will be available via: 'object->runtime.mesh_eval' */
+ }
+}
+
+static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob)
+{
+ uint32_t eval_flags = DEG_get_eval_flags_for_id(depsgraph, &ob->id);
+
+ if (eval_flags & DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY) {
+ BKE_shrinkwrap_compute_boundary_data(ob->runtime.mesh_eval);
}
- return false;
}
-#endif
static void mesh_build_data(
- Scene *scene, Object *ob, CustomDataMask dataMask,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask,
const bool build_shapekey_layers, const bool need_mapping)
{
BLI_assert(ob->type == OB_MESH);
@@ -2644,18 +1999,18 @@ static void mesh_build_data(
BKE_object_free_derived_caches(ob);
BKE_object_sculpt_modifiers_changed(ob);
-#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(scene, ob, false)) {
- dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
- }
-#endif
-
mesh_calc_modifiers(
- scene, ob, NULL, false, 1, need_mapping, dataMask, -1, true, build_shapekey_layers,
- true,
- &ob->derivedDeform, &ob->derivedFinal);
+ depsgraph, scene, ob, NULL, 1, need_mapping, dataMask, -1, true, build_shapekey_layers,
+ &ob->runtime.mesh_deform_eval, &ob->runtime.mesh_eval);
+
+ mesh_finalize_eval(ob);
- DM_set_object_boundbox(ob, ob->derivedFinal);
+ /* TODO(campbell): remove these copies, they are expected in various places over the code. */
+ ob->derivedDeform = CDDM_from_mesh_ex(ob->runtime.mesh_deform_eval, CD_REFERENCE, CD_MASK_MESH);
+ ob->derivedFinal = CDDM_from_mesh_ex(ob->runtime.mesh_eval, CD_REFERENCE, CD_MASK_MESH);
+
+ BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
+ BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
ob->derivedFinal->needsFree = 0;
ob->derivedDeform->needsFree = 0;
@@ -2665,49 +2020,53 @@ static void mesh_build_data(
if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
/* create PBVH immediately (would be created on the fly too,
* but this avoids waiting on first stroke) */
-
- BKE_sculpt_update_mesh_elements(scene, scene->toolsettings->sculpt, ob, false, false);
+ /* XXX Disabled for now.
+ * This can create horrible nasty bugs by generating re-entrant call of mesh_get_eval_final! */
+// BKE_sculpt_update_mesh_elements(depsgraph, scene, scene->toolsettings->sculpt, ob, false, false);
}
BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS));
+
+ mesh_build_extra_data(depsgraph, ob);
}
-static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
+static void editbmesh_build_data(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
{
BKE_object_free_derived_caches(obedit);
BKE_object_sculpt_modifiers_changed(obedit);
BKE_editmesh_free_derivedmesh(em);
-#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(scene, obedit, false)) {
- dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
- }
-#endif
+ Mesh *me_cage;
+ Mesh *me_final;
editbmesh_calc_modifiers(
- scene, obedit, em, dataMask,
- &em->derivedCage, &em->derivedFinal);
+ depsgraph, scene, obedit, em, dataMask,
+ &me_cage, &me_final);
+
+ em->mesh_eval_final = me_final;
+ em->mesh_eval_cage = me_cage;
- DM_set_object_boundbox(obedit, em->derivedFinal);
+ BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
em->lastDataMask = dataMask;
- em->derivedFinal->needsFree = 0;
- em->derivedCage->needsFree = 0;
- BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS));
+ BLI_assert(!(em->mesh_eval_final->runtime.cd_dirty_vert & DM_DIRTY_NORMALS));
}
-static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *r_need_mapping)
+static CustomDataMask object_get_datamask(const Depsgraph *depsgraph, Object *ob, bool *r_need_mapping)
{
- Object *actob = scene->basact ? scene->basact->object : NULL;
+ ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ Object *actob = view_layer->basact ? DEG_get_original_object(view_layer->basact->object) : NULL;
CustomDataMask mask = ob->customdata_mask;
if (r_need_mapping) {
*r_need_mapping = false;
}
- if (ob == actob) {
+ if (DEG_get_original_object(ob) == actob) {
bool editing = BKE_paint_select_face_test(ob);
/* weight paint and face select need original indices because of selection buffer drawing */
@@ -2726,7 +2085,7 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *
}
if (ob->mode & OB_MODE_WEIGHT_PAINT) {
- mask |= CD_MASK_PREVIEW_MLOOPCOL;
+ mask |= CD_MASK_MDEFORMVERT;
}
if (ob->mode & OB_MODE_EDIT)
@@ -2737,151 +2096,208 @@ static CustomDataMask object_get_datamask(const Scene *scene, Object *ob, bool *
}
void makeDerivedMesh(
- Scene *scene, Object *ob, BMEditMesh *em,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em,
CustomDataMask dataMask, const bool build_shapekey_layers)
{
bool need_mapping;
- dataMask |= object_get_datamask(scene, ob, &need_mapping);
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
if (em) {
- editbmesh_build_data(scene, ob, em, dataMask);
+ editbmesh_build_data(depsgraph, scene, ob, em, dataMask);
}
else {
- mesh_build_data(scene, ob, dataMask, build_shapekey_layers, need_mapping);
+ mesh_build_data(depsgraph, scene, ob, dataMask, build_shapekey_layers, need_mapping);
}
}
/***/
-DerivedMesh *mesh_get_derived_final(Scene *scene, Object *ob, CustomDataMask dataMask)
+#ifdef USE_DERIVEDMESH
+/* Deprecated DM, use: 'mesh_get_eval_final'. */
+DerivedMesh *mesh_get_derived_final(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
bool need_mapping;
- dataMask |= object_get_datamask(scene, ob, &need_mapping);
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
if (!ob->derivedFinal ||
((dataMask & ob->lastDataMask) != dataMask) ||
(need_mapping != ob->lastNeedMapping))
{
- mesh_build_data(scene, ob, dataMask, false, need_mapping);
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
}
if (ob->derivedFinal) { BLI_assert(!(ob->derivedFinal->dirty & DM_DIRTY_NORMALS)); }
return ob->derivedFinal;
}
+#endif
+Mesh *mesh_get_eval_final(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
+{
+ /* if there's no evaluated mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ bool need_mapping;
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
+
+ if (!ob->runtime.mesh_eval ||
+ ((dataMask & ob->lastDataMask) != dataMask) ||
+ (need_mapping != ob->lastNeedMapping))
+ {
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
+ }
+
+ if (ob->runtime.mesh_eval) { BLI_assert(!(ob->runtime.mesh_eval->runtime.cd_dirty_vert & CD_MASK_NORMAL)); }
+ return ob->runtime.mesh_eval;
+}
-DerivedMesh *mesh_get_derived_deform(Scene *scene, Object *ob, CustomDataMask dataMask)
+#ifdef USE_DERIVEDMESH
+/* Deprecated DM, use: 'mesh_get_eval_deform' instead. */
+DerivedMesh *mesh_get_derived_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
bool need_mapping;
- dataMask |= object_get_datamask(scene, ob, &need_mapping);
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
if (!ob->derivedDeform ||
((dataMask & ob->lastDataMask) != dataMask) ||
(need_mapping != ob->lastNeedMapping))
{
- mesh_build_data(scene, ob, dataMask, false, need_mapping);
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
}
return ob->derivedDeform;
}
+#endif
+Mesh *mesh_get_eval_deform(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
+{
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ bool need_mapping;
-DerivedMesh *mesh_create_derived_render(Scene *scene, Object *ob, CustomDataMask dataMask)
+ dataMask |= object_get_datamask(depsgraph, ob, &need_mapping);
+
+ if (!ob->runtime.mesh_deform_eval ||
+ ((dataMask & ob->lastDataMask) != dataMask) ||
+ (need_mapping != ob->lastNeedMapping))
+ {
+ mesh_build_data(depsgraph, scene, ob, dataMask, false, need_mapping);
+ }
+
+ return ob->runtime.mesh_deform_eval;
+}
+
+
+#ifdef USE_DERIVEDMESH
+/* Deprecated, use `mesh_create_eval_final_render` instead. */
+DerivedMesh *mesh_create_derived_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
DerivedMesh *final;
- mesh_calc_modifiers(
- scene, ob, NULL, true, 1, false, dataMask, -1, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false,
NULL, &final);
return final;
}
-
-DerivedMesh *mesh_create_derived_index_render(Scene *scene, Object *ob, CustomDataMask dataMask, int index)
+#endif
+Mesh *mesh_create_eval_final_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask)
{
- DerivedMesh *final;
+ Mesh *final;
mesh_calc_modifiers(
- scene, ob, NULL, true, 1, false, dataMask, index, false, false, false,
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false,
NULL, &final);
return final;
}
-DerivedMesh *mesh_create_derived_view(
- Scene *scene, Object *ob,
- CustomDataMask dataMask)
+#ifdef USE_DERIVEDMESH
+/* Deprecated, use `mesh_create_eval_final_index_render` instead. */
+DerivedMesh *mesh_create_derived_index_render(struct Depsgraph *depsgraph, Scene *scene, Object *ob, CustomDataMask dataMask, int index)
{
DerivedMesh *final;
- /* XXX hack
- * psys modifier updates particle state when called during dupli-list generation,
- * which can lead to wrong transforms. This disables particle system modifier execution.
- */
- ob->transflag |= OB_NO_PSYS_UPDATE;
-
- mesh_calc_modifiers(
- scene, ob, NULL, false, 1, false, dataMask, -1, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, NULL, 1, false, dataMask, index, false, false,
NULL, &final);
- ob->transflag &= ~OB_NO_PSYS_UPDATE;
-
return final;
}
-
-DerivedMesh *mesh_create_derived_no_deform(
- Scene *scene, Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask)
+#endif
+Mesh *mesh_create_eval_final_index_render(
+ struct Depsgraph *depsgraph, struct Scene *scene,
+ struct Object *ob, CustomDataMask dataMask, int index)
{
- DerivedMesh *final;
+ Mesh *final;
mesh_calc_modifiers(
- scene, ob, vertCos, false, 0, false, dataMask, -1, false, false, false,
+ depsgraph, scene, ob, NULL, 1, false, dataMask, index, false, false,
NULL, &final);
return final;
}
-DerivedMesh *mesh_create_derived_no_virtual(
- Scene *scene, Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask)
+#ifdef USE_DERIVEDMESH
+/* Deprecated, use `mesh_create_eval_final_view` instead. */
+DerivedMesh *mesh_create_derived_view(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, CustomDataMask dataMask)
{
DerivedMesh *final;
- mesh_calc_modifiers(
- scene, ob, vertCos, false, -1, false, dataMask, -1, false, false, false,
+ /* XXX hack
+ * psys modifier updates particle state when called during dupli-list generation,
+ * which can lead to wrong transforms. This disables particle system modifier execution.
+ */
+ ob->transflag |= OB_NO_PSYS_UPDATE;
+
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false,
NULL, &final);
+ ob->transflag &= ~OB_NO_PSYS_UPDATE;
+
return final;
}
+#endif
-DerivedMesh *mesh_create_derived_physics(
- Scene *scene, Object *ob, float (*vertCos)[3],
- CustomDataMask dataMask)
+Mesh *mesh_create_eval_final_view(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, CustomDataMask dataMask)
{
- DerivedMesh *final;
+ Mesh *final;
+
+ /* XXX hack
+ * psys modifier updates particle state when called during dupli-list generation,
+ * which can lead to wrong transforms. This disables particle system modifier execution.
+ */
+ ob->transflag |= OB_NO_PSYS_UPDATE;
mesh_calc_modifiers(
- scene, ob, vertCos, false, -1, true, dataMask, -1, false, false, false,
+ depsgraph, scene, ob, NULL, 1, false, dataMask, -1, false, false,
NULL, &final);
+ ob->transflag &= ~OB_NO_PSYS_UPDATE;
+
return final;
}
-DerivedMesh *mesh_create_derived_no_deform_render(
- Scene *scene, Object *ob,
- float (*vertCos)[3],
- CustomDataMask dataMask)
+DerivedMesh *mesh_create_derived_no_deform(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ float (*vertCos)[3], CustomDataMask dataMask)
{
DerivedMesh *final;
- mesh_calc_modifiers(
- scene, ob, vertCos, true, 0, false, dataMask, -1, false, false, false,
+ mesh_calc_modifiers_dm(
+ depsgraph, scene, ob, vertCos, 0, false, dataMask, -1, false, false,
NULL, &final);
return final;
@@ -2889,74 +2305,48 @@ DerivedMesh *mesh_create_derived_no_deform_render(
/***/
-DerivedMesh *editbmesh_get_derived_cage_and_final(
- Scene *scene, Object *obedit, BMEditMesh *em,
+Mesh *editbmesh_get_eval_cage_and_final(
+ struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em,
CustomDataMask dataMask,
/* return args */
- DerivedMesh **r_final)
+ Mesh **r_final)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit, NULL);
+ dataMask |= object_get_datamask(depsgraph, obedit, NULL);
- if (!em->derivedCage ||
+ if (!em->mesh_eval_cage ||
(em->lastDataMask & dataMask) != dataMask)
{
- editbmesh_build_data(scene, obedit, em, dataMask);
+ editbmesh_build_data(depsgraph, scene, obedit, em, dataMask);
}
- *r_final = em->derivedFinal;
- if (em->derivedFinal) { BLI_assert(!(em->derivedFinal->dirty & DM_DIRTY_NORMALS)); }
- return em->derivedCage;
+ *r_final = em->mesh_eval_final;
+ if (em->mesh_eval_final) { BLI_assert(!(em->mesh_eval_final->runtime.cd_dirty_vert & DM_DIRTY_NORMALS)); }
+ return em->mesh_eval_cage;
}
-DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
+Mesh *editbmesh_get_eval_cage(
+ struct Depsgraph *depsgraph, Scene *scene, Object *obedit, BMEditMesh *em,
+ CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
* the data we need, rebuild the derived mesh
*/
- dataMask |= object_get_datamask(scene, obedit, NULL);
+ dataMask |= object_get_datamask(depsgraph, obedit, NULL);
- if (!em->derivedCage ||
+ if (!em->mesh_eval_cage ||
(em->lastDataMask & dataMask) != dataMask)
{
- editbmesh_build_data(scene, obedit, em, dataMask);
+ editbmesh_build_data(depsgraph, scene, obedit, em, dataMask);
}
- return em->derivedCage;
-}
-
-DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDataMask data_mask)
-{
- return getEditDerivedBMesh(em, obedit, data_mask, NULL);
+ return em->mesh_eval_cage;
}
/***/
-/* get derived mesh from an object, using editbmesh if available. */
-DerivedMesh *object_get_derived_final(Object *ob, const bool for_render)
-{
- if (for_render) {
- /* TODO(sergey): use proper derived render here in the future. */
- return ob->derivedFinal;
- }
-
- /* only return the editmesh if its from this object because
- * we don't a mesh from another object's modifier stack: T43122 */
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_btmesh;
- if (em && (em->ob == ob)) {
- DerivedMesh *dm = em->derivedFinal;
- return dm;
- }
- }
-
- return ob->derivedFinal;
-}
-
-
/* UNUSED */
#if 0
@@ -3038,289 +2428,24 @@ static void make_vertexcos__mapFunc(
}
}
-void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos)
+void mesh_get_mapped_verts_coords(Mesh *me_eval, float (*r_cos)[3], const int totcos)
{
- if (dm->foreachMappedVert) {
+ if (me_eval->runtime.deformed_only == false) {
MappedUserData userData;
memset(r_cos, 0, sizeof(*r_cos) * totcos);
userData.vertexcos = r_cos;
userData.vertex_visit = BLI_BITMAP_NEW(totcos, "vertexcos flags");
- dm->foreachMappedVert(dm, make_vertexcos__mapFunc, &userData, DM_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(me_eval, make_vertexcos__mapFunc, &userData, MESH_FOREACH_NOP);
MEM_freeN(userData.vertex_visit);
}
else {
- int i;
- for (i = 0; i < totcos; i++) {
- dm->getVertCo(dm, i, r_cos[i]);
+ MVert *mv = me_eval->mvert;
+ for (int i = 0; i < totcos; i++, mv++) {
+ copy_v3_v3(r_cos[i], mv->co);
}
}
}
-/* ******************* GLSL ******************** */
-
-/** \name Tangent Space Calculation
- * \{ */
-
-/* Necessary complexity to handle looptri's as quads for correct tangents */
-#define USE_LOOPTRI_DETECT_QUADS
-
-typedef struct {
- float (*precomputedFaceNormals)[3];
- float (*precomputedLoopNormals)[3];
- const MLoopTri *looptri;
- MLoopUV *mloopuv; /* texture coordinates */
- MPoly *mpoly; /* indices */
- MLoop *mloop; /* indices */
- MVert *mvert; /* vertices & normals */
- float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
-#endif
-
-} SGLSLMeshToTangent;
-
-/* interface */
-#include "mikktspace.h"
-
-static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
-#else
- return pMesh->numTessFaces;
-#endif
-}
-
-static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
-#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- if (pMesh->face_as_quad_map) {
- const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- return 4;
- }
- }
- return 3;
-#else
- UNUSED_VARS(pContext, face_num);
- return 3;
-#endif
-}
-
-static void dm_ts_GetPosition(
- const SMikkTSpaceContext *pContext, float r_co[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
- const float *co;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
- copy_v3_v3(r_co, co);
-}
-
-static void dm_ts_GetTextureCoordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- if (pMesh->mloopuv != NULL) {
- const float *uv = pMesh->mloopuv[loop_index].uv;
- copy_v2_v2(r_uv, uv);
- }
- else {
- const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
- }
-}
-
-static void dm_ts_GetNormal(
- const SMikkTSpaceContext *pContext, float r_no[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
-finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
- }
- else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
- }
- else {
-#ifdef USE_LOOPTRI_DETECT_QUADS
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- normal_quad_v3(
- r_no,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
- pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
- }
- else
-#endif
- {
- normal_tri_v3(
- r_no,
- pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
- pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
- }
- }
- }
- else {
- const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
- normal_short_to_float_v3(r_no, no);
- }
-}
-
-static void dm_ts_SetTSpace(
- const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
- const MLoopTri *lt;
- int loop_index;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
- const MPoly *mp = &pMesh->mpoly[lt->poly];
- if (mp->totloop == 4) {
- loop_index = mp->loopstart + vert_index;
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = &pMesh->looptri[face_num];
- }
-#else
- lt = &pMesh->looptri[face_num];
-#endif
- loop_index = lt->tri[vert_index];
-
- float *pRes;
-
-finally:
- pRes = pMesh->tangent[loop_index];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
-}
-
-void DM_calc_tangents_names_from_gpu(
- const GPUVertexAttribs *gattribs,
- char (*tangent_names)[MAX_NAME], int *r_tangent_names_count)
-{
- int count = 0;
- for (int b = 0; b < gattribs->totlayer; b++) {
- if (gattribs->layer[b].type == CD_TANGENT) {
- strcpy(tangent_names[count++], gattribs->layer[b].name);
- }
- }
- *r_tangent_names_count = count;
-}
-
-static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- struct SGLSLMeshToTangent *mesh2tangent = taskdata;
- /* new computation method */
- {
- SMikkTSpaceContext sContext = {NULL};
- SMikkTSpaceInterface sInterface = {NULL};
-
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = dm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = dm_ts_GetPosition;
- sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = dm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
-
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
-}
-
void DM_add_named_tangent_layer_for_uv(
CustomData *uv_data, CustomData *tan_data, int numLoopData,
const char *layer_name)
@@ -3334,805 +2459,107 @@ void DM_add_named_tangent_layer_for_uv(
}
}
-/**
- * Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
- * Also, we calculate tangent_mask that works as a descriptor of tangents state.
- * If tangent_mask has changed, then recalculate tangents.
- */
-void DM_calc_loop_tangents_step_0(
- const CustomData *loopData, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count,
- bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
- char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
-{
- /* Active uv in viewport */
- int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
- *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
- ract_uv_name[0] = 0;
- if (*ract_uv_n != -1) {
- strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
- }
-
- /* Active tangent in render */
- *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
- rren_uv_name[0] = 0;
- if (*rren_uv_n != -1) {
- strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
- }
-
- /* If active tangent not in tangent_names we take it into account */
- *rcalc_act = false;
- *rcalc_ren = false;
- for (int i = 0; i < tangent_names_count; i++) {
- if (tangent_names[i][0] == 0) {
- calc_active_tangent = true;
- }
- }
- if (calc_active_tangent) {
- *rcalc_act = true;
- *rcalc_ren = true;
- for (int i = 0; i < tangent_names_count; i++) {
- if (STREQ(ract_uv_name, tangent_names[i]))
- *rcalc_act = false;
- if (STREQ(rren_uv_name, tangent_names[i]))
- *rcalc_ren = false;
- }
- }
- *rtangent_mask = 0;
-
- const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
- for (int n = 0; n < uv_layer_num; n++) {
- const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
- bool add = false;
- for (int i = 0; i < tangent_names_count; i++) {
- if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
- add = true;
- break;
- }
- }
- if ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
- (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name)))
- {
- add = true;
- }
- if (add)
- *rtangent_mask |= 1 << n;
- }
-
- if (uv_layer_num == 0)
- *rtangent_mask |= DM_TANGENT_MASK_ORCO;
-}
-
void DM_calc_loop_tangents(
DerivedMesh *dm, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count)
-{
- int act_uv_n = -1;
- int ren_uv_n = -1;
- bool calc_act = false;
- bool calc_ren = false;
- char act_uv_name[MAX_NAME];
- char ren_uv_name[MAX_NAME];
- short tangent_mask = 0;
- DM_calc_loop_tangents_step_0(
- &dm->loopData, calc_active_tangent, tangent_names, tangent_names_count,
- &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
- if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
- /* Check we have all the needed layers */
- MPoly *mpoly = dm->getPolyArray(dm);
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- int totface = dm->getNumLoopTri(dm);
- /* Allocate needed tangent layers */
- for (int i = 0; i < tangent_names_count; i++)
- if (tangent_names[i][0])
- DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, tangent_names[i]);
- if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1)
- CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, "");
- if (calc_act && act_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, act_uv_name);
- if (calc_ren && ren_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&dm->loopData, &dm->loopData, dm->numLoopData, ren_uv_name);
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (totface != dm->getNumPolys(dm)) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_malloc_arrayN(totface, sizeof(int), __func__);
- int k, j;
- for (k = 0, j = 0; j < totface; k++, j++) {
- face_as_quad_map[k] = j;
- /* step over all quads */
- if (mpoly[looptri[j].poly].totloop == 4) {
- j++; /* skips the nest looptri */
- }
- }
- num_face_as_quad_map = k;
- }
- else {
- num_face_as_quad_map = totface;
- }
-#endif
-
- /* Calculation */
- {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
-
- dm->tangent_mask = 0;
- /* Calculate tangent layers */
- SGLSLMeshToTangent data_array[MAX_MTFACE];
- const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
- for (int n = 0; n < tangent_layer_num; n++) {
- int index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
- BLI_assert(n < MAX_MTFACE);
- SGLSLMeshToTangent *mesh2tangent = &data_array[n];
- mesh2tangent->numTessFaces = totface;
-#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent->face_as_quad_map = face_as_quad_map;
- mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
-#endif
- mesh2tangent->mvert = dm->getVertArray(dm);
- mesh2tangent->mpoly = dm->getPolyArray(dm);
- mesh2tangent->mloop = dm->getLoopArray(dm);
- mesh2tangent->looptri = dm->getLoopTriArray(dm);
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- mesh2tangent->precomputedLoopNormals = dm->getLoopDataArray(dm, CD_NORMAL);
- mesh2tangent->precomputedFaceNormals = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
- mesh2tangent->orco = NULL;
- mesh2tangent->mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
-
- /* Fill the resulting tangent_mask */
- if (!mesh2tangent->mloopuv) {
- mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
- if (!mesh2tangent->orco)
- continue;
-
- dm->tangent_mask |= DM_TANGENT_MASK_ORCO;
- }
- else {
- int uv_ind = CustomData_get_named_layer_index(&dm->loopData, CD_MLOOPUV, dm->loopData.layers[index].name);
- int uv_start = CustomData_get_layer_index(&dm->loopData, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- dm->tangent_mask |= 1 << (uv_ind - uv_start);
- }
-
- mesh2tangent->tangent = dm->loopData.layers[index].data;
- BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
- }
-
- BLI_assert(dm->tangent_mask == tangent_mask);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- }
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (face_as_quad_map) {
- MEM_freeN(face_as_quad_map);
- }
-#undef USE_LOOPTRI_DETECT_QUADS
-
-#endif
-
- /* Update active layer index */
- int act_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, act_uv_n);
- if (act_uv_index != -1) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[act_uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
-
- /* Update render layer index */
- int ren_uv_index = CustomData_get_layer_index_n(&dm->loopData, CD_MLOOPUV, ren_uv_n);
- if (ren_uv_index != -1) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, dm->loopData.layers[ren_uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
- }
-}
-
-/** \} */
-
-
-void DM_calc_auto_bump_scale(DerivedMesh *dm)
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len)
{
- /* int totvert = dm->getNumVerts(dm); */ /* UNUSED */
- int totface = dm->getNumTessFaces(dm);
-
- MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getTessFaceArray(dm);
- MTFace *mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
-
- if (mtface) {
- double dsum = 0.0;
- int nr_accumulated = 0;
- int f;
-
- for (f = 0; f < totface; f++) {
- {
- float *verts[4], *tex_coords[4];
- const int nr_verts = mface[f].v4 != 0 ? 4 : 3;
- bool is_degenerate;
- int i;
-
- verts[0] = mvert[mface[f].v1].co; verts[1] = mvert[mface[f].v2].co; verts[2] = mvert[mface[f].v3].co;
- tex_coords[0] = mtface[f].uv[0]; tex_coords[1] = mtface[f].uv[1]; tex_coords[2] = mtface[f].uv[2];
- if (nr_verts == 4) {
- verts[3] = mvert[mface[f].v4].co;
- tex_coords[3] = mtface[f].uv[3];
- }
-
- /* discard degenerate faces */
- is_degenerate = 0;
- if (equals_v3v3(verts[0], verts[1]) ||
- equals_v3v3(verts[0], verts[2]) ||
- equals_v3v3(verts[1], verts[2]) ||
- equals_v2v2(tex_coords[0], tex_coords[1]) ||
- equals_v2v2(tex_coords[0], tex_coords[2]) ||
- equals_v2v2(tex_coords[1], tex_coords[2]))
- {
- is_degenerate = 1;
- }
-
- /* verify last vertex as well if this is a quad */
- if (is_degenerate == 0 && nr_verts == 4) {
- if (equals_v3v3(verts[3], verts[0]) ||
- equals_v3v3(verts[3], verts[1]) ||
- equals_v3v3(verts[3], verts[2]) ||
- equals_v2v2(tex_coords[3], tex_coords[0]) ||
- equals_v2v2(tex_coords[3], tex_coords[1]) ||
- equals_v2v2(tex_coords[3], tex_coords[2]))
- {
- is_degenerate = 1;
- }
-
- /* verify the winding is consistent */
- if (is_degenerate == 0) {
- float prev_edge[2];
- bool is_signed = 0;
- sub_v2_v2v2(prev_edge, tex_coords[0], tex_coords[3]);
-
- i = 0;
- while (is_degenerate == 0 && i < 4) {
- float cur_edge[2], signed_area;
- sub_v2_v2v2(cur_edge, tex_coords[(i + 1) & 0x3], tex_coords[i]);
- signed_area = cross_v2v2(prev_edge, cur_edge);
-
- if (i == 0) {
- is_signed = (signed_area < 0.0f) ? 1 : 0;
- }
- else if ((is_signed != 0) != (signed_area < 0.0f)) {
- is_degenerate = 1;
- }
-
- if (is_degenerate == 0) {
- copy_v2_v2(prev_edge, cur_edge);
- i++;
- }
- }
- }
- }
-
- /* proceed if not a degenerate face */
- if (is_degenerate == 0) {
- int nr_tris_to_pile = 0;
- /* quads split at shortest diagonal */
- int offs = 0; /* initial triangulation is 0,1,2 and 0, 2, 3 */
- if (nr_verts == 4) {
- float pos_len_diag0, pos_len_diag1;
-
- pos_len_diag0 = len_squared_v3v3(verts[2], verts[0]);
- pos_len_diag1 = len_squared_v3v3(verts[3], verts[1]);
-
- if (pos_len_diag1 < pos_len_diag0) {
- offs = 1; // alter split
- }
- else if (pos_len_diag0 == pos_len_diag1) { /* do UV check instead */
- float tex_len_diag0, tex_len_diag1;
-
- tex_len_diag0 = len_squared_v2v2(tex_coords[2], tex_coords[0]);
- tex_len_diag1 = len_squared_v2v2(tex_coords[3], tex_coords[1]);
-
- if (tex_len_diag1 < tex_len_diag0) {
- offs = 1; /* alter split */
- }
- }
- }
- nr_tris_to_pile = nr_verts - 2;
- if (nr_tris_to_pile == 1 || nr_tris_to_pile == 2) {
- const int indices[6] = {offs + 0, offs + 1, offs + 2, offs + 0, offs + 2, (offs + 3) & 0x3 };
- int t;
- for (t = 0; t < nr_tris_to_pile; t++) {
- float f2x_area_uv;
- const float *p0 = verts[indices[t * 3 + 0]];
- const float *p1 = verts[indices[t * 3 + 1]];
- const float *p2 = verts[indices[t * 3 + 2]];
-
- float edge_t0[2], edge_t1[2];
- sub_v2_v2v2(edge_t0, tex_coords[indices[t * 3 + 1]], tex_coords[indices[t * 3 + 0]]);
- sub_v2_v2v2(edge_t1, tex_coords[indices[t * 3 + 2]], tex_coords[indices[t * 3 + 0]]);
-
- f2x_area_uv = fabsf(cross_v2v2(edge_t0, edge_t1));
- if (f2x_area_uv > FLT_EPSILON) {
- float norm[3], v0[3], v1[3], f2x_surf_area, fsurf_ratio;
- sub_v3_v3v3(v0, p1, p0);
- sub_v3_v3v3(v1, p2, p0);
- cross_v3_v3v3(norm, v0, v1);
-
- f2x_surf_area = len_v3(norm);
- fsurf_ratio = f2x_surf_area / f2x_area_uv; /* tri area divided by texture area */
-
- nr_accumulated++;
- dsum += (double)(fsurf_ratio);
- }
- }
- }
- }
- }
- }
-
- /* finalize */
- {
- const float avg_area_ratio = (nr_accumulated > 0) ? ((float)(dsum / nr_accumulated)) : 1.0f;
- const float use_as_render_bump_scale = sqrtf(avg_area_ratio); // use width of average surface ratio as your bump scale
- dm->auto_bump_scale = use_as_render_bump_scale;
- }
- }
- else {
- dm->auto_bump_scale = 1.0f;
- }
+ BKE_mesh_calc_loop_tangent_ex(
+ dm->getVertArray(dm),
+ dm->getPolyArray(dm), dm->getNumPolys(dm),
+ dm->getLoopArray(dm),
+ dm->getLoopTriArray(dm), dm->getNumLoopTri(dm),
+ &dm->loopData,
+ calc_active_tangent,
+ tangent_names, tangent_names_len,
+ CustomData_get_layer(&dm->polyData, CD_NORMAL),
+ dm->getLoopDataArray(dm, CD_NORMAL),
+ dm->getVertDataArray(dm, CD_ORCO), /* may be NULL */
+ /* result */
+ &dm->loopData, dm->getNumLoops(dm),
+ &dm->tangent_mask);
}
-void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, DMVertexAttribs *attribs)
+void DM_init_origspace(DerivedMesh *dm)
{
- CustomData *vdata, *ldata;
- int a, b, layer;
- const bool is_editmesh = (dm->type == DM_TYPE_EDITBMESH);
-
- /* From the layers requested by the GLSL shader, figure out which ones are
- * actually available for this derivedmesh, and retrieve the pointers */
-
- memset(attribs, 0, sizeof(DMVertexAttribs));
-
- vdata = &dm->vertData;
- ldata = dm->getLoopDataLayout(dm);
-
- /* calc auto bump scale if necessary */
- if (dm->auto_bump_scale <= 0.0f)
- DM_calc_auto_bump_scale(dm);
-
- char tangent_names[MAX_MTFACE][MAX_NAME];
- int tangent_names_count;
- /* Add a tangent layer/layers. */
- DM_calc_tangents_names_from_gpu(gattribs, tangent_names, &tangent_names_count);
-
- if (tangent_names_count)
- dm->calcLoopTangents(dm, false, (const char (*)[MAX_NAME])tangent_names, tangent_names_count);
-
- for (b = 0; b < gattribs->totlayer; b++) {
- int type = gattribs->layer[b].type;
- layer = -1;
- if (type == CD_AUTO_FROM_NAME) {
- /* We need to deduct what exact layer is used.
- *
- * We do it based on the specified name.
- */
- if (gattribs->layer[b].name[0]) {
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- type = CD_MTFACE;
- if (layer == -1) {
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- type = CD_MCOL;
- }
- if (layer == -1) {
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- type = CD_TANGENT;
- }
- if (layer == -1) {
- continue;
- }
- }
- else {
- /* Fall back to the UV layer, which matches old behavior. */
- type = CD_MTFACE;
- }
- }
- if (type == CD_MTFACE) {
- /* uv coordinates */
- if (layer == -1) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPUV, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
- }
-
- a = attribs->tottface++;
-
- if (layer != -1) {
- attribs->tface[a].array = is_editmesh ? NULL : ldata->layers[layer].data;
- attribs->tface[a].em_offset = ldata->layers[layer].offset;
- }
- else {
- attribs->tface[a].array = NULL;
- attribs->tface[a].em_offset = -1;
- }
-
- attribs->tface[a].gl_index = gattribs->layer[b].glindex;
- attribs->tface[a].gl_info_index = gattribs->layer[b].glinfoindoex;
- attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
- }
- else if (type == CD_MCOL) {
- if (layer == -1) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(ldata, CD_MLOOPCOL, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(ldata, CD_MLOOPCOL);
- }
-
- a = attribs->totmcol++;
-
- if (layer != -1) {
- attribs->mcol[a].array = is_editmesh ? NULL : ldata->layers[layer].data;
- /* odd, store the offset for a different layer type here, but editmode draw code expects it */
- attribs->mcol[a].em_offset = ldata->layers[layer].offset;
- }
- else {
- attribs->mcol[a].array = NULL;
- attribs->mcol[a].em_offset = -1;
- }
-
- attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
- attribs->mcol[a].gl_info_index = gattribs->layer[b].glinfoindoex;
- }
- else if (type == CD_TANGENT) {
- /* note, even with 'is_editmesh' this uses the derived-meshes loop data */
- if (layer == -1) {
- if (gattribs->layer[b].name[0])
- layer = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, gattribs->layer[b].name);
- else
- layer = CustomData_get_active_layer_index(&dm->loopData, CD_TANGENT);
- }
+ const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
- a = attribs->tottang++;
+ OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP);
+ const int numpoly = dm->getNumPolys(dm);
+ // const int numloop = dm->getNumLoops(dm);
+ MVert *mv = dm->getVertArray(dm);
+ MLoop *ml = dm->getLoopArray(dm);
+ MPoly *mp = dm->getPolyArray(dm);
+ int i, j, k;
- if (layer != -1) {
- attribs->tang[a].array = dm->loopData.layers[layer].data;
- attribs->tang[a].em_offset = dm->loopData.layers[layer].offset;
- }
- else {
- attribs->tang[a].array = NULL;
- attribs->tang[a].em_offset = -1;
- }
+ float (*vcos_2d)[2] = NULL;
+ BLI_array_staticdeclare(vcos_2d, 64);
- attribs->tang[a].gl_index = gattribs->layer[b].glindex;
- attribs->tang[a].gl_info_index = gattribs->layer[b].glinfoindoex;
- }
- else if (type == CD_ORCO) {
- /* original coordinates */
- if (layer == -1) {
- layer = CustomData_get_layer_index(vdata, CD_ORCO);
- }
- attribs->totorco = 1;
+ for (i = 0; i < numpoly; i++, mp++) {
+ OrigSpaceLoop *lof = lof_array + mp->loopstart;
- if (layer != -1) {
- attribs->orco.array = vdata->layers[layer].data;
- attribs->orco.em_offset = vdata->layers[layer].offset;
- }
- else {
- attribs->orco.array = NULL;
- attribs->orco.em_offset = -1;
+ if (mp->totloop == 3 || mp->totloop == 4) {
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ copy_v2_v2(lof->uv, default_osf[j]);
}
-
- attribs->orco.gl_index = gattribs->layer[b].glindex;
- attribs->orco.gl_texco = gattribs->layer[b].gltexco;
- attribs->orco.gl_info_index = gattribs->layer[b].glinfoindoex;
- }
- }
-}
-
-/**
- * Set vertex shader attribute inputs for a particular tessface vert
- *
- * \param a: tessface index
- * \param index: vertex index
- * \param vert: corner index (0, 1, 2, 3)
- * \param loop: absolute loop corner index
- */
-void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop)
-{
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- int b;
-
- UNUSED_VARS(a, vert);
-
- /* orco texture coordinates */
- if (attribs->totorco) {
- /*const*/ float (*array)[3] = attribs->orco.array;
- const float *orco = (array) ? array[index] : zero;
-
- if (attribs->orco.gl_texco)
- glTexCoord3fv(orco);
- else
- glVertexAttrib3fv(attribs->orco.gl_index, orco);
- }
-
- /* uv texture coordinates */
- for (b = 0; b < attribs->tottface; b++) {
- const float *uv;
-
- if (attribs->tface[b].array) {
- const MLoopUV *mloopuv = &attribs->tface[b].array[loop];
- uv = mloopuv->uv;
- }
- else {
- uv = zero;
- }
-
- if (attribs->tface[b].gl_texco)
- glTexCoord2fv(uv);
- else
- glVertexAttrib2fv(attribs->tface[b].gl_index, uv);
- }
-
- /* vertex colors */
- for (b = 0; b < attribs->totmcol; b++) {
- GLfloat col[4];
-
- if (attribs->mcol[b].array) {
- const MLoopCol *cp = &attribs->mcol[b].array[loop];
- rgba_uchar_to_float(col, &cp->r);
}
else {
- zero_v4(col);
- }
-
- glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
- }
-
- /* tangent for normal mapping */
- for (b = 0; b < attribs->tottang; b++) {
- if (attribs->tang[b].array) {
- /*const*/ float (*array)[4] = attribs->tang[b].array;
- const float *tang = (array) ? array[loop] : zero;
- glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
- }
- }
-}
-
-void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs)
-{
- int i;
- if (attribs->totorco) {
- if (attribs->orco.gl_info_index != -1) {
- glUniform1i(attribs->orco.gl_info_index, 0);
- }
- }
- for (i = 0; i < attribs->tottface; i++) {
- if (attribs->tface[i].gl_info_index != -1) {
- glUniform1i(attribs->tface[i].gl_info_index, 0);
- }
- }
- for (i = 0; i < attribs->totmcol; i++) {
- if (attribs->mcol[i].gl_info_index != -1) {
- glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
- }
- }
-
- for (i = 0; i < attribs->tottang; i++) {
- if (attribs->tang[i].gl_info_index != -1) {
- glUniform1i(attribs->tang[i].gl_info_index, 0);
- }
- }
-}
-
-/* Set object's bounding box based on DerivedMesh min/max data */
-void DM_set_object_boundbox(Object *ob, DerivedMesh *dm)
-{
- float min[3], max[3];
-
- INIT_MINMAX(min, max);
- dm->getMinMax(dm, min, max);
-
- if (!ob->bb)
- ob->bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
-
- BKE_boundbox_init_from_minmax(ob->bb, min, max);
-
- ob->bb->flag &= ~BOUNDBOX_DIRTY;
-}
-
-/* --- NAVMESH (begin) --- */
-#ifdef WITH_GAMEENGINE
-
-/* BMESH_TODO, navmesh is not working right currently
- * All tools set this as MPoly data, but derived mesh currently draws from MFace (tessface)
- *
- * Proposed solution, rather then copy CD_RECAST into the MFace array,
- * use ORIGINDEX to get the original poly index and then get the CD_RECAST
- * data from the original me->mpoly layer. - campbell
- */
-
-
-BLI_INLINE int navmesh_bit(int a, int b)
-{
- return (a & (1 << b)) >> b;
-}
-
-BLI_INLINE void navmesh_intToCol(int i, float col[3])
-{
- int r = navmesh_bit(i, 0) + navmesh_bit(i, 3) * 2 + 1;
- int g = navmesh_bit(i, 1) + navmesh_bit(i, 4) * 2 + 1;
- int b = navmesh_bit(i, 2) + navmesh_bit(i, 5) * 2 + 1;
- col[0] = 1 - r * 63.0f / 255.0f;
- col[1] = 1 - g * 63.0f / 255.0f;
- col[2] = 1 - b * 63.0f / 255.0f;
-}
-
-static void navmesh_drawColored(DerivedMesh *dm)
-{
- int a, glmode;
- MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT);
- MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE);
- int *polygonIdx = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
- float col[3];
+ MLoop *l = &ml[mp->loopstart];
+ float p_nor[3], co[3];
+ float mat[3][3];
- if (!polygonIdx)
- return;
+ float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX};
+ float translate[2], scale[2];
-#if 0
- //UI_ThemeColor(TH_WIRE);
- glLineWidth(2.0);
- dm->drawEdges(dm, 0, 1);
-#endif
+ BKE_mesh_calc_poly_normal(mp, l, mv, p_nor);
+ axis_dominant_v3_to_m3(mat, p_nor);
- /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */
- {
- DEBUG_VBO("Using legacy code. drawNavMeshColored\n");
- glBegin(glmode = GL_QUADS);
- for (a = 0; a < dm->numTessFaceData; a++, mface++) {
- int new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES;
- int pi = polygonIdx[a];
- if (pi <= 0) {
- zero_v3(col);
- }
- else {
- navmesh_intToCol(pi, col);
- }
+ BLI_array_clear(vcos_2d);
+ BLI_array_reserve(vcos_2d, mp->totloop);
+ for (j = 0; j < mp->totloop; j++, l++) {
+ mul_v3_m3v3(co, mat, mv[l->v].co);
+ copy_v2_v2(vcos_2d[j], co);
- if (new_glmode != glmode) {
- glEnd();
- glBegin(glmode = new_glmode);
- }
- glColor3fv(col);
- glVertex3fv(mvert[mface->v1].co);
- glVertex3fv(mvert[mface->v2].co);
- glVertex3fv(mvert[mface->v3].co);
- if (mface->v4) {
- glVertex3fv(mvert[mface->v4].co);
+ for (k = 0; k < 2; k++) {
+ if (co[k] > max[k])
+ max[k] = co[k];
+ else if (co[k] < min[k])
+ min[k] = co[k];
+ }
}
- }
- glEnd();
- }
-}
-
-static void navmesh_DM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex UNUSED(setDrawOptions),
- DMCompareDrawOptions UNUSED(compareDrawOptions),
- void *UNUSED(userData), DMDrawFlag UNUSED(flag))
-{
- navmesh_drawColored(dm);
-}
-static void navmesh_DM_drawFacesSolid(
- DerivedMesh *dm,
- float (*partial_redraw_planes)[4],
- bool UNUSED(fast), DMSetMaterial UNUSED(setMaterial))
-{
- UNUSED_VARS(partial_redraw_planes);
+ /* Brings min to (0, 0). */
+ negate_v2_v2(translate, min);
- //drawFacesSolid_original(dm, partial_redraw_planes, fast, setMaterial);
- navmesh_drawColored(dm);
-}
+ /* Scale will bring max to (1, 1). */
+ sub_v2_v2v2(scale, max, min);
+ if (scale[0] == 0.0f)
+ scale[0] = 1e-9f;
+ if (scale[1] == 0.0f)
+ scale[1] = 1e-9f;
+ invert_v2(scale);
-static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
-{
- DerivedMesh *result;
- int maxFaces = dm->getNumPolys(dm);
- int *recastData;
- int vertsPerPoly = 0, nverts = 0, ndtris = 0, npolys = 0;
- float *verts = NULL;
- unsigned short *dtris = NULL, *dmeshes = NULL, *polys = NULL;
- int *dtrisToPolysMap = NULL, *dtrisToTrisMap = NULL, *trisToFacesMap = NULL;
- int res;
-
- result = CDDM_copy(dm);
- if (!CustomData_has_layer(&result->polyData, CD_RECAST)) {
- int *sourceRecastData = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
- if (sourceRecastData) {
- CustomData_add_layer_named(&result->polyData, CD_RECAST, CD_DUPLICATE,
- sourceRecastData, maxFaces, "recastData");
- }
- }
- recastData = (int *)CustomData_get_layer(&result->polyData, CD_RECAST);
-
- /* note: This is not good design! - really should not be doing this */
- result->drawFacesTex = navmesh_DM_drawFacesTex;
- result->drawFacesSolid = navmesh_DM_drawFacesSolid;
-
-
- /* process mesh */
- res = buildNavMeshDataByDerivedMesh(dm, &vertsPerPoly, &nverts, &verts, &ndtris, &dtris,
- &npolys, &dmeshes, &polys, &dtrisToPolysMap, &dtrisToTrisMap,
- &trisToFacesMap);
- if (res) {
- size_t polyIdx;
-
- /* invalidate concave polygon */
- for (polyIdx = 0; polyIdx < (size_t)npolys; polyIdx++) {
- unsigned short *poly = &polys[polyIdx * 2 * vertsPerPoly];
- if (!polyIsConvex(poly, vertsPerPoly, verts)) {
- /* set negative polygon idx to all faces */
- unsigned short *dmesh = &dmeshes[4 * polyIdx];
- unsigned short tbase = dmesh[2];
- unsigned short tnum = dmesh[3];
- unsigned short ti;
-
- for (ti = 0; ti < tnum; ti++) {
- unsigned short triidx = dtrisToTrisMap[tbase + ti];
- unsigned short faceidx = trisToFacesMap[triidx];
- if (recastData[faceidx] > 0) {
- recastData[faceidx] = -recastData[faceidx];
- }
- }
+ /* Finally, transform all vcos_2d into ((0, 0), (1, 1)) square and assign them as origspace. */
+ for (j = 0; j < mp->totloop; j++, lof++) {
+ add_v2_v2v2(lof->uv, vcos_2d[j], translate);
+ mul_v2_v2(lof->uv, scale);
}
}
}
- else {
- printf("Navmesh: Unable to generate valid Navmesh");
- }
- /* clean up */
- if (verts != NULL)
- MEM_freeN(verts);
- if (dtris != NULL)
- MEM_freeN(dtris);
- if (dmeshes != NULL)
- MEM_freeN(dmeshes);
- if (polys != NULL)
- MEM_freeN(polys);
- if (dtrisToPolysMap != NULL)
- MEM_freeN(dtrisToPolysMap);
- if (dtrisToTrisMap != NULL)
- MEM_freeN(dtrisToTrisMap);
- if (trisToFacesMap != NULL)
- MEM_freeN(trisToFacesMap);
-
- return result;
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ BLI_array_free(vcos_2d);
}
-#endif /* WITH_GAMEENGINE */
-
-/* --- NAVMESH (end) --- */
-
-
-void DM_init_origspace(DerivedMesh *dm)
+static void mesh_init_origspace(Mesh *mesh)
{
const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
- OrigSpaceLoop *lof_array = CustomData_get_layer(&dm->loopData, CD_ORIGSPACE_MLOOP);
- const int numpoly = dm->getNumPolys(dm);
- // const int numloop = dm->getNumLoops(dm);
- MVert *mv = dm->getVertArray(dm);
- MLoop *ml = dm->getLoopArray(dm);
- MPoly *mp = dm->getPolyArray(dm);
+ OrigSpaceLoop *lof_array = CustomData_get_layer(&mesh->ldata, CD_ORIGSPACE_MLOOP);
+ const int numpoly = mesh->totpoly;
+ // const int numloop = mesh->totloop;
+ MVert *mv = mesh->mvert;
+ MLoop *ml = mesh->mloop;
+ MPoly *mp = mesh->mpoly;
int i, j, k;
float (*vcos_2d)[2] = NULL;
@@ -4190,12 +2617,11 @@ void DM_init_origspace(DerivedMesh *dm)
}
}
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ BKE_mesh_tessface_clear(mesh);
BLI_array_free(vcos_2d);
}
-
/* derivedmesh info printing function,
* to help track down differences DM output */
@@ -4235,7 +2661,6 @@ char *DM_debug_info(DerivedMesh *dm)
BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm);
switch (dm->type) {
case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break;
- case DM_TYPE_EDITBMESH: tstr = "DM_TYPE_EDITMESH"; break;
case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break;
default: tstr = "UNKNOWN"; break;
}
@@ -4334,84 +2759,3 @@ bool DM_is_valid(DerivedMesh *dm)
}
#endif /* NDEBUG */
-
-/* -------------------------------------------------------------------- */
-
-MVert *DM_get_vert_array(DerivedMesh *dm, bool *allocated)
-{
- CustomData *vert_data = dm->getVertDataLayout(dm);
- MVert *mvert = CustomData_get_layer(vert_data, CD_MVERT);
- *allocated = false;
-
- if (mvert == NULL) {
- mvert = MEM_malloc_arrayN(dm->getNumVerts(dm), sizeof(MVert), "dmvh vert data array");
- dm->copyVertArray(dm, mvert);
- *allocated = true;
- }
-
- return mvert;
-}
-
-MEdge *DM_get_edge_array(DerivedMesh *dm, bool *allocated)
-{
- CustomData *edge_data = dm->getEdgeDataLayout(dm);
- MEdge *medge = CustomData_get_layer(edge_data, CD_MEDGE);
- *allocated = false;
-
- if (medge == NULL) {
- medge = MEM_malloc_arrayN(dm->getNumEdges(dm), sizeof(MEdge), "dm medge data array");
- dm->copyEdgeArray(dm, medge);
- *allocated = true;
- }
-
- return medge;
-}
-
-MLoop *DM_get_loop_array(DerivedMesh *dm, bool *r_allocated)
-{
- CustomData *loop_data = dm->getLoopDataLayout(dm);
- MLoop *mloop = CustomData_get_layer(loop_data, CD_MLOOP);
- *r_allocated = false;
-
- if (mloop == NULL) {
- mloop = MEM_malloc_arrayN(dm->getNumLoops(dm), sizeof(MLoop), "dm loop data array");
- dm->copyLoopArray(dm, mloop);
- *r_allocated = true;
- }
-
- return mloop;
-}
-
-MPoly *DM_get_poly_array(DerivedMesh *dm, bool *r_allocated)
-{
- CustomData *poly_data = dm->getPolyDataLayout(dm);
- MPoly *mpoly = CustomData_get_layer(poly_data, CD_MPOLY);
- *r_allocated = false;
-
- if (mpoly == NULL) {
- mpoly = MEM_malloc_arrayN(dm->getNumPolys(dm), sizeof(MPoly), "dm poly data array");
- dm->copyPolyArray(dm, mpoly);
- *r_allocated = true;
- }
-
- return mpoly;
-}
-
-MFace *DM_get_tessface_array(DerivedMesh *dm, bool *r_allocated)
-{
- CustomData *tessface_data = dm->getTessFaceDataLayout(dm);
- MFace *mface = CustomData_get_layer(tessface_data, CD_MFACE);
- *r_allocated = false;
-
- if (mface == NULL) {
- int numTessFaces = dm->getNumTessFaces(dm);
-
- if (numTessFaces > 0) {
- mface = MEM_malloc_arrayN(numTessFaces, sizeof(MFace), "bvh mface data array");
- dm->copyTessFaceArray(dm, mface);
- *r_allocated = true;
- }
- }
-
- return mface;
-}
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 00e5d17128b..115ed29818a 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -55,7 +55,6 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -65,6 +64,8 @@
#include "BKE_main.h"
#include "BKE_object.h"
+#include "DEG_depsgraph_build.h"
+
#include "BIK_api.h"
#include "RNA_access.h"
@@ -425,7 +426,7 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
return NULL;
/* See if this channel exists */
- chan = BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name));
+ chan = BKE_pose_channel_find_name(pose, name);
if (chan) {
return chan;
}
@@ -453,7 +454,9 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name)
chan->protectflag = OB_LOCK_ROT4D; /* lock by components by default */
BLI_addtail(&pose->chanbase, chan);
- BKE_pose_channels_hash_free(pose);
+ if (pose->chanhash) {
+ BLI_ghash_insert(pose->chanhash, chan->name, chan);
+ }
return chan;
}
@@ -581,12 +584,16 @@ void BKE_pose_copy_data_ex(bPose **dst, const bPose *src, const int flag, const
if (copy_constraints) {
BKE_constraints_copy_ex(&listb, &pchan->constraints, flag, true); // BKE_constraints_copy NULLs listb
pchan->constraints = listb;
- pchan->mpath = NULL; /* motion paths should not get copied yet... */
+
+ /* XXX: This is needed for motionpath drawing to work. Dunno why it was setting to null before... */
+ pchan->mpath = animviz_copy_motionpath(pchan->mpath);
}
if (pchan->prop) {
pchan->prop = IDP_CopyProperty_ex(pchan->prop, flag);
}
+
+ pchan->draw_data = NULL; /* Drawing cache, no need to copy. */
}
/* for now, duplicate Bone Groups too when doing this */
@@ -780,6 +787,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)
@@ -849,39 +859,6 @@ void BKE_pose_free(bPose *pose)
BKE_pose_free_ex(pose, true);
}
-static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan)
-{
- bConstraint *pcon, *con;
-
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- copy_v3_v3(pchan->eul, chan->eul);
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- copy_qt_qt(pchan->quat, chan->quat);
- pchan->rotmode = chan->rotmode;
- copy_m4_m4(pchan->chan_mat, (float(*)[4])chan->chan_mat);
- copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
- pchan->flag = chan->flag;
-
- pchan->roll1 = chan->roll1;
- pchan->roll2 = chan->roll2;
- pchan->curveInX = chan->curveInX;
- pchan->curveInY = chan->curveInY;
- pchan->curveOutX = chan->curveOutX;
- pchan->curveOutY = chan->curveOutY;
- pchan->ease1 = chan->ease1;
- pchan->ease2 = chan->ease2;
- pchan->scaleIn = chan->scaleIn;
- pchan->scaleOut = chan->scaleOut;
-
- con = chan->constraints.first;
- for (pcon = pchan->constraints.first; pcon && con; pcon = pcon->next, con = con->next) {
- pcon->enforce = con->enforce;
- pcon->headtail = con->headtail;
- }
-}
-
/**
* Copy the internal members of each pose channel including constraints
* and ID-Props, used when duplicating bones in editmode.
@@ -910,7 +887,6 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
pchan->iklinweight = pchan_from->iklinweight;
/* bbone settings (typically not animated) */
- pchan->bboneflag = pchan_from->bboneflag;
pchan->bbone_next = pchan_from->bbone_next;
pchan->bbone_prev = pchan_from->bbone_prev;
@@ -1323,25 +1299,6 @@ short action_get_item_transforms(bAction *act, Object *ob, bPoseChannel *pchan,
/* ************** Pose Management Tools ****************** */
-/* Copy the data from the action-pose (src) into the pose */
-/* both args are assumed to be valid */
-/* exported to game engine */
-/* Note! this assumes both poses are aligned, this isn't always true when dealing with user poses */
-void extract_pose_from_pose(bPose *pose, const bPose *src)
-{
- const bPoseChannel *schan;
- bPoseChannel *pchan = pose->chanbase.first;
-
- if (pose == src) {
- printf("extract_pose_from_pose source and target are the same\n");
- return;
- }
-
- for (schan = src->chanbase.first; (schan && pchan); schan = schan->next, pchan = pchan->next) {
- copy_pose_channel_data(pchan, schan);
- }
-}
-
/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */
void BKE_pose_rest(bPose *pose)
{
@@ -1370,6 +1327,36 @@ void BKE_pose_rest(bPose *pose)
}
}
+void BKE_pose_copyesult_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom)
+{
+ copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
+ copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
+
+ /* used for local constraints */
+ copy_v3_v3(pchanto->loc, pchanfrom->loc);
+ copy_qt_qt(pchanto->quat, pchanfrom->quat);
+ copy_v3_v3(pchanto->eul, pchanfrom->eul);
+ copy_v3_v3(pchanto->size, pchanfrom->size);
+
+ copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
+ copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
+
+ pchanto->roll1 = pchanfrom->roll1;
+ pchanto->roll2 = pchanfrom->roll2;
+ pchanto->curveInX = pchanfrom->curveInX;
+ pchanto->curveInY = pchanfrom->curveInY;
+ pchanto->curveOutX = pchanfrom->curveOutX;
+ pchanto->curveOutY = pchanfrom->curveOutY;
+ pchanto->ease1 = pchanfrom->ease1;
+ pchanto->ease2 = pchanfrom->ease2;
+ pchanto->scaleIn = pchanfrom->scaleIn;
+ pchanto->scaleOut = pchanfrom->scaleOut;
+
+ pchanto->rotmode = pchanfrom->rotmode;
+ pchanto->flag = pchanfrom->flag;
+ pchanto->protectflag = pchanfrom->protectflag;
+}
+
/* both poses should be in sync */
bool BKE_pose_copy_result(bPose *to, bPose *from)
{
@@ -1388,34 +1375,8 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) {
pchanto = BKE_pose_channel_find_name(to, pchanfrom->name);
- if (pchanto) {
- copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat);
- copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat);
-
- /* used for local constraints */
- copy_v3_v3(pchanto->loc, pchanfrom->loc);
- copy_qt_qt(pchanto->quat, pchanfrom->quat);
- copy_v3_v3(pchanto->eul, pchanfrom->eul);
- copy_v3_v3(pchanto->size, pchanfrom->size);
-
- copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head);
- copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail);
-
- pchanto->roll1 = pchanfrom->roll1;
- pchanto->roll2 = pchanfrom->roll2;
- pchanto->curveInX = pchanfrom->curveInX;
- pchanto->curveInY = pchanfrom->curveInY;
- pchanto->curveOutX = pchanfrom->curveOutX;
- pchanto->curveOutY = pchanfrom->curveOutY;
- pchanto->ease1 = pchanfrom->ease1;
- pchanto->ease2 = pchanfrom->ease2;
- pchanto->scaleIn = pchanfrom->scaleIn;
- pchanto->scaleOut = pchanfrom->scaleOut;
-
- pchanto->rotmode = pchanfrom->rotmode;
- pchanto->flag = pchanfrom->flag;
- pchanto->protectflag = pchanfrom->protectflag;
- pchanto->bboneflag = pchanfrom->bboneflag;
+ if (pchanto != NULL) {
+ BKE_pose_copyesult_pchan_result(pchanto, pchanfrom);
}
}
return true;
@@ -1428,7 +1389,7 @@ void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
/* Depsgraph components depends on actual pose state,
* if pose was changed depsgraph is to be updated as well.
*/
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
}
/* For the calculation of the effects of an Action at the given frame on an object
@@ -1486,7 +1447,7 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c
RNA_id_pointer_create(&workob->id, &id_ptr);
/* execute action for this group only */
- animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe);
+ animsys_evaluate_action_group(&id_ptr, act, agrp, cframe);
}
else {
AnimData adt = {NULL};
@@ -1498,6 +1459,6 @@ void what_does_obaction(Object *ob, Object *workob, bPose *pose, bAction *act, c
adt.action = act;
/* execute effects of Action on to workob (or it's PoseChannels) */
- BKE_animsys_evaluate_animdata(NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(NULL, NULL, &workob->id, &adt, cframe, ADT_RECALC_ANIM);
}
}
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index e35af19facb..89291b158b7 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -35,6 +35,7 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_dlrbTree.h"
#include "BLT_translation.h"
@@ -43,18 +44,29 @@
#include "DNA_key_types.h"
#include "DNA_scene_types.h"
+#include "BKE_anim.h"
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
-#include "BKE_anim.h"
#include "BKE_report.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+#include "DEG_depsgraph_build.h"
+
+#include "GPU_batch.h"
+
// XXX bad level call...
+extern short compare_ak_cfraPtr(void *node, void *data);
+extern void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct DLRBT_Tree *keys, int saction_flag);
+extern void action_to_keylist(struct AnimData *adt, struct bAction *act, struct DLRBT_Tree *keys, int saction_flag);
/* --------------------- */
/* forward declarations */
@@ -87,6 +99,8 @@ void animviz_settings_init(bAnimVizSettings *avs)
avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS);
avs->path_step = 1;
+
+ avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS;
}
/* ------------------- */
@@ -102,6 +116,10 @@ void animviz_free_motionpath_cache(bMotionPath *mpath)
if (mpath->points)
MEM_freeN(mpath->points);
+ GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
+
/* reset the relevant parameters */
mpath->points = NULL;
mpath->length = 0;
@@ -125,6 +143,27 @@ void animviz_free_motionpath(bMotionPath *mpath)
/* ------------------- */
+/* Make a copy of motionpath data, so that viewing with copy on write works */
+bMotionPath *animviz_copy_motionpath(const bMotionPath *mpath_src)
+{
+ bMotionPath *mpath_dst;
+
+ if (mpath_src == NULL)
+ return NULL;
+
+ mpath_dst = MEM_dupallocN(mpath_src);
+ mpath_dst->points = MEM_dupallocN(mpath_src->points);
+
+ /* should get recreated on draw... */
+ mpath_dst->points_vbo = NULL;
+ mpath_dst->batch_line = NULL;
+ mpath_dst->batch_points = NULL;
+
+ return mpath_dst;
+}
+
+/* ------------------- */
+
/**
* Setup motion paths for the given data.
* \note Only used when explicitly calculating paths on bones which may/may not be consider already
@@ -207,7 +246,7 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec
mpath->color[1] = 0.0;
mpath->color[2] = 0.0;
- mpath->line_thickness = 1;
+ mpath->line_thickness = 2;
mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */
/* allocate a cache */
@@ -228,8 +267,16 @@ typedef struct MPathTarget {
bMotionPath *mpath; /* motion path in question */
+ DLRBT_Tree keys; /* temp, to know where the keyframes are */
+
+ /* Original (Source Objects) */
Object *ob; /* source object */
bPoseChannel *pchan; /* source posechannel (if applicable) */
+
+ /* "Evaluated" Copies (these come from the background COW copie
+ * that provide all the coordinates we want to save off)
+ */
+ Object *ob_eval; /* evaluated object */
} MPathTarget;
/* ........ */
@@ -273,127 +320,95 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
/* ........ */
-/* Note on evaluation optimizations:
- * Optimization's currently used here play tricks with the depsgraph in order to try and
- * evaluate as few objects as strictly necessary to get nicer performance under standard
- * production conditions. For those people who really need the accurate version,
- * disable the ifdef (i.e. 1 -> 0) and comment out the call to motionpaths_calc_optimise_depsgraph()
- */
-
-/* tweak the object ordering to trick depsgraph into making MotionPath calculations run faster */
-static void motionpaths_calc_optimise_depsgraph(Main *bmain, Scene *scene, ListBase *targets)
-{
- Base *base, *baseNext;
- MPathTarget *mpt;
-
- /* make sure our temp-tag isn't already in use */
- for (base = scene->base.first; base; base = base->next)
- base->object->flag &= ~BA_TEMP_TAG;
-
- /* for each target, dump its object to the start of the list if it wasn't moved already */
- for (mpt = targets->first; mpt; mpt = mpt->next) {
- for (base = scene->base.first; base; base = baseNext) {
- baseNext = base->next;
-
- if ((base->object == mpt->ob) && !(mpt->ob->flag & BA_TEMP_TAG)) {
- BLI_remlink(&scene->base, base);
- BLI_addhead(&scene->base, base);
-
- mpt->ob->flag |= BA_TEMP_TAG;
-
- /* we really don't need to continue anymore once this happens, but this line might really 'break' */
- break;
- }
- }
- }
-
- /* "brew me a list that's sorted a bit faster now depsy" */
- DAG_scene_relations_rebuild(bmain, scene);
-}
-
/* update scene for current frame */
-static void motionpaths_calc_update_scene(Main *bmain, Scene *scene)
+static void motionpaths_calc_update_scene(Main *bmain,
+ struct Depsgraph *depsgraph)
{
-#if 1 // 'production' optimizations always on
- /* rigid body simulation needs complete update to work correctly for now */
- /* RB_TODO investigate if we could avoid updating everything */
- if (BKE_scene_check_rigidbody_active(scene)) {
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
- }
- else { /* otherwise we can optimize by restricting updates */
- Base *base, *last = NULL;
-
- /* only stuff that moves or needs display still */
- DAG_scene_update_flags(bmain, scene, scene->lay, true, false);
-
- /* find the last object with the tag
- * - all those afterwards are assumed to not be relevant for our calculations
- */
- /* optimize further by moving out... */
- for (base = scene->base.first; base; base = base->next) {
- if (base->object->flag & BA_TEMP_TAG)
- last = base;
- }
-
- /* perform updates for tagged objects */
- /* XXX: this will break if rigs depend on scene or other data that
- * is animated but not attached to/updatable from objects */
- for (base = scene->base.first; base; base = base->next) {
- /* update this object */
- BKE_object_handle_update(bmain, bmain->eval_ctx, scene, base->object);
-
- /* if this is the last one we need to update, let's stop to save some time */
- if (base == last)
- break;
- }
- }
-#else // original, 'always correct' version
- /* do all updates
+ /* Do all updates
* - if this is too slow, resort to using a more efficient way
* that doesn't force complete update, but for now, this is the
* most accurate way!
+ *
+ * TODO(segey): Bring back partial updates, which became impossible
+ * with the new depsgraph due to unsorted nature of bases.
+ *
+ * TODO(sergey): Use evaluation context dedicated to motion paths.
*/
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); /* XXX this is the best way we can get anything moving */
-#endif
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
/* ........ */
/* perform baking for the targets on the current frame */
-static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets)
+static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
{
MPathTarget *mpt;
/* for each target, check if it can be baked on the current frame */
for (mpt = targets->first; mpt; mpt = mpt->next) {
bMotionPath *mpath = mpt->mpath;
- bMotionPathVert *mpv;
/* current frame must be within the range the cache works for
* - is inclusive of the first frame, but not the last otherwise we get buffer overruns
*/
- if ((CFRA < mpath->start_frame) || (CFRA >= mpath->end_frame))
+ if ((cframe < mpath->start_frame) || (cframe >= mpath->end_frame)) {
continue;
+ }
/* get the relevant cache vert to write to */
- mpv = mpath->points + (CFRA - mpath->start_frame);
+ bMotionPathVert *mpv = mpath->points + (cframe - mpath->start_frame);
- /* pose-channel or object path baking? */
+ Object *ob_eval = mpt->ob_eval;
+
+ /* Lookup evaluated pose channel, here because the depsgraph
+ * evaluation can change them so they are not cached in mpt. */
+ bPoseChannel *pchan_eval = NULL;
if (mpt->pchan) {
+ pchan_eval = BKE_pose_channel_find_name(ob_eval->pose, mpt->pchan->name);
+ }
+
+ /* pose-channel or object path baking? */
+ if (pchan_eval) {
/* heads or tails */
if (mpath->flag & MOTIONPATH_FLAG_BHEAD) {
- copy_v3_v3(mpv->co, mpt->pchan->pose_head);
+ copy_v3_v3(mpv->co, pchan_eval->pose_head);
}
else {
- copy_v3_v3(mpv->co, mpt->pchan->pose_tail);
+ copy_v3_v3(mpv->co, pchan_eval->pose_tail);
}
/* result must be in worldspace */
- mul_m4_v3(mpt->ob->obmat, mpv->co);
+ mul_m4_v3(ob_eval->obmat, mpv->co);
}
else {
/* worldspace object location */
- copy_v3_v3(mpv->co, mpt->ob->obmat[3]);
+ copy_v3_v3(mpv->co, ob_eval->obmat[3]);
+ }
+
+ float mframe = (float)(cframe);
+
+ /* Tag if it's a keyframe */
+ if (BLI_dlrbTree_search_exact(&mpt->keys, compare_ak_cfraPtr, &mframe)) {
+ mpv->flag |= MOTIONPATH_VERT_KEY;
+ }
+
+ /* Incremental update on evaluated object if possible, for fast updating
+ * while dragging in transform. */
+ bMotionPath *mpath_eval = NULL;
+ if (mpt->pchan) {
+ mpath_eval = (pchan_eval) ? pchan_eval->mpath : NULL;
+ }
+ else {
+ mpath_eval = ob_eval->mpath;
+ }
+
+ if (mpath_eval && mpath_eval->length == mpath->length) {
+ bMotionPathVert *mpv_eval = mpath_eval->points + (cframe - mpath_eval->start_frame);
+ *mpv_eval = *mpv;
+
+ GPU_VERTBUF_DISCARD_SAFE(mpath_eval->points_vbo);
+ GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_line);
+ GPU_BATCH_DISCARD_SAFE(mpath_eval->batch_points);
}
}
}
@@ -404,50 +419,110 @@ static void motionpaths_calc_bake_targets(Scene *scene, ListBase *targets)
* - recalc: whether we need to
*/
/* TODO: include reports pointer? */
-void animviz_calc_motionpaths(Main *bmain, Scene *scene, ListBase *targets)
+void animviz_calc_motionpaths(Depsgraph *depsgraph,
+ Main *bmain,
+ Scene *scene,
+ ListBase *targets,
+ bool restore,
+ bool current_frame_only)
{
- MPathTarget *mpt;
- int sfra, efra;
- int cfra;
-
/* sanity check */
if (ELEM(NULL, targets, targets->first))
return;
- /* set frame values */
- cfra = CFRA;
- sfra = efra = cfra;
-
- /* TODO: this method could be improved...
+ /* Compute frame range to bake within.
+ * TODO: this method could be improved...
* 1) max range for standard baking
* 2) minimum range for recalc baking (i.e. between keyframes, but how?) */
- for (mpt = targets->first; mpt; mpt = mpt->next) {
+ int sfra = INT_MAX;
+ int efra = INT_MIN;
+
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
/* try to increase area to do (only as much as needed) */
sfra = MIN2(sfra, mpt->mpath->start_frame);
efra = MAX2(efra, mpt->mpath->end_frame);
}
- if (efra <= sfra) return;
- /* optimize the depsgraph for faster updates */
- /* TODO: whether this is used should depend on some setting for the level of optimizations used */
- motionpaths_calc_optimise_depsgraph(bmain, scene, targets);
+ if (efra <= sfra) {
+ return;
+ }
+
+ /* Limit frame range if we are updating just the current frame. */
+ /* set frame values */
+ int cfra = CFRA;
+ if (current_frame_only) {
+ if (cfra < sfra || cfra > efra) {
+ return;
+ }
+ sfra = efra = cfra;
+ }
+
+ /* get copies of objects/bones to get the calculated results from
+ * (for copy-on-write evaluation), so that we actually get some results
+ */
+ // TODO: Create a copy of background depsgraph that only contain these entities, and only evaluates them..
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob);
+
+ AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id);
+
+ /* build list of all keyframes in active action for object or pchan */
+ BLI_dlrbTree_init(&mpt->keys);
+
+ if (adt) {
+ bAnimVizSettings *avs;
+
+ /* get pointer to animviz settings for each target */
+ if (mpt->pchan)
+ avs = &mpt->ob->pose->avs;
+ else
+ avs = &mpt->ob->avs;
+
+ /* it is assumed that keyframes for bones are all grouped in a single group
+ * unless an option is set to always use the whole action
+ */
+ if ((mpt->pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) {
+ bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
+
+ if (agrp) {
+ agroup_to_keylist(adt, agrp, &mpt->keys, 0);
+ }
+ }
+ else {
+ action_to_keylist(adt, adt->action, &mpt->keys, 0);
+ }
+ }
+ }
/* calculate path over requested range */
+ printf("Calculating MotionPaths between frames %d - %d (%d frames)\n", sfra, efra, efra - sfra + 1);
for (CFRA = sfra; CFRA <= efra; CFRA++) {
- /* update relevant data for new frame */
- motionpaths_calc_update_scene(bmain, scene);
+ if (current_frame_only) {
+ /* For current frame, only update tagged. */
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+ }
+ else {
+ /* Update relevant data for new frame. */
+ motionpaths_calc_update_scene(bmain, depsgraph);
+ }
/* perform baking for targets */
- motionpaths_calc_bake_targets(scene, targets);
+ motionpaths_calc_bake_targets(targets, CFRA);
}
/* reset original environment */
+ /* NOTE: We don't always need to reevaluate the main scene, as the depsgraph
+ * may be a temporary one that works on a subset of the data. We always have
+ * to resoture the current frame though. */
CFRA = cfra;
- motionpaths_calc_update_scene(bmain, scene);
+ if (!current_frame_only && restore) {
+ motionpaths_calc_update_scene(bmain, depsgraph);
+ }
/* clear recalc flags from targets */
- for (mpt = targets->first; mpt; mpt = mpt->next) {
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
bAnimVizSettings *avs;
+ bMotionPath *mpath = mpt->mpath;
/* get pointer to animviz settings for each target */
if (mpt->pchan)
@@ -457,6 +532,14 @@ void animviz_calc_motionpaths(Main *bmain, Scene *scene, ListBase *targets)
/* clear the flag requesting recalculation of targets */
avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
+
+ /* Clean temp data */
+ BLI_dlrbTree_free(&mpt->keys);
+
+ /* Free previous batches to force update. */
+ GPU_VERTBUF_DISCARD_SAFE(mpath->points_vbo);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_line);
+ GPU_BATCH_DISCARD_SAFE(mpath->batch_points);
}
}
@@ -494,18 +577,18 @@ void calc_curvepath(Object *ob, ListBase *nurbs)
return;
}
- if (ob->curve_cache->path) free_path(ob->curve_cache->path);
- ob->curve_cache->path = NULL;
+ if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path);
+ ob->runtime.curve_cache->path = NULL;
/* weak! can only use first curve */
- bl = ob->curve_cache->bev.first;
+ bl = ob->runtime.curve_cache->bev.first;
if (bl == NULL || !bl->nr) {
return;
}
nu = nurbs->first;
- ob->curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
+ ob->runtime.curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath");
/* if POLY: last vertice != first vertice */
cycl = (bl->poly != -1);
@@ -622,15 +705,15 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua
if (ob == NULL || ob->type != OB_CURVE) return 0;
cu = ob->data;
- if (ob->curve_cache == NULL || ob->curve_cache->path == NULL || ob->curve_cache->path->data == NULL) {
+ if (ob->runtime.curve_cache == NULL || ob->runtime.curve_cache->path == NULL || ob->runtime.curve_cache->path->data == NULL) {
printf("no path!\n");
return 0;
}
- path = ob->curve_cache->path;
+ path = ob->runtime.curve_cache->path;
pp = path->data;
/* test for cyclic */
- bl = ob->curve_cache->bev.first;
+ bl = ob->runtime.curve_cache->bev.first;
if (!bl) return 0;
if (!bl->nr) return 0;
if (bl->poly > -1) cycl = 1;
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 05cb10ab7a4..d4355546c19 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -57,27 +57,27 @@
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
-#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
-#include "BKE_nla.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
-#include "BKE_library.h"
+#include "BKE_nla.h"
#include "BKE_report.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#include "nla_private.h"
#include "atomic_ops.h"
-#include "DEG_depsgraph.h"
-
/* ***************************************** */
/* AnimData API */
@@ -97,6 +97,7 @@ bool id_type_can_have_animdata(const short id_type)
case ID_MA: case ID_TE: case ID_NT:
case ID_LA: case ID_CA: case ID_WO:
case ID_LS:
+ case ID_LP:
case ID_SPK:
case ID_SCE:
case ID_MC:
@@ -245,11 +246,14 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
}
/* free nla data */
- BKE_nla_tracks_free(&adt->nla_tracks);
+ BKE_nla_tracks_free(&adt->nla_tracks, do_id_user);
/* free drivers - stored as a list of F-Curves */
free_fcurves(&adt->drivers);
+ /* free driver array cache */
+ MEM_SAFE_FREE(adt->driver_array);
+
/* free overrides */
/* TODO... */
@@ -262,11 +266,18 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
/* Copying -------------------------------------------- */
-/* Make a copy of the given AnimData - to be used when copying datablocks */
-AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
+/**
+ * Make a copy of the given AnimData - to be used when copying datablocks.
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
+ * \return The copied animdata.
+ */
+AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
{
AnimData *dadt;
+ const bool do_action = (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0;
+ const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+
/* sanity check before duplicating struct */
if (adt == NULL)
return NULL;
@@ -278,16 +289,17 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
BKE_id_copy_ex(bmain, (ID *)dadt->action, (ID **)&dadt->action, 0, false);
BKE_id_copy_ex(bmain, (ID *)dadt->tmpact, (ID **)&dadt->tmpact, 0, false);
}
- else {
+ else if (do_id_user) {
id_us_plus((ID *)dadt->action);
id_us_plus((ID *)dadt->tmpact);
}
/* duplicate NLA data */
- BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks);
+ BKE_nla_tracks_copy(bmain, &dadt->nla_tracks, &adt->nla_tracks, flag);
/* duplicate drivers (F-Curves) */
copy_fcurves(&dadt->drivers, &adt->drivers);
+ dadt->driver_array = NULL;
/* don't copy overrides */
BLI_listbase_clear(&dadt->overrides);
@@ -296,19 +308,23 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const bool do_action)
return dadt;
}
-bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const bool do_action)
+/**
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
+ * \return true is succesfully copied.
+ */
+bool BKE_animdata_copy_id(Main *bmain, ID *id_to, ID *id_from, const int flag)
{
AnimData *adt;
if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name)))
return false;
- BKE_animdata_free(id_to, true);
+ BKE_animdata_free(id_to, (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0);
adt = BKE_animdata_from_id(id_from);
if (adt) {
IdAdtTemplate *iat = (IdAdtTemplate *)id_to;
- iat->adt = BKE_animdata_copy(bmain, adt, do_action);
+ iat->adt = BKE_animdata_copy(bmain, adt, flag);
}
return true;
@@ -368,7 +384,7 @@ void BKE_animdata_merge_copy(
if (src->nla_tracks.first) {
ListBase tracks = {NULL, NULL};
- BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks);
+ BKE_nla_tracks_copy(bmain, &tracks, &src->nla_tracks, 0);
BLI_movelisttolist(&dst->nla_tracks, &tracks);
}
@@ -604,36 +620,8 @@ char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *p
Object *ob = CTX_data_active_object(C);
if (ob && id) {
- /* only id-types which can be remapped to go through objects should be considered */
- switch (GS(id->name)) {
- case ID_TE: /* textures */
- {
- Material *ma = give_current_material(ob, ob->actcol);
- Tex *tex = give_current_material_texture(ma);
-
- /* assumes: texture will only be shown if it is active material's active texture it's ok */
- if ((ID *)tex == id) {
- char name_esc_ma[(sizeof(ma->id.name) - 2) * 2];
- char name_esc_tex[(sizeof(tex->id.name) - 2) * 2];
-
- BLI_strescape(name_esc_ma, ma->id.name + 2, sizeof(name_esc_ma));
- BLI_strescape(name_esc_tex, tex->id.name + 2, sizeof(name_esc_tex));
-
- /* create new path */
- // TODO: use RNA path functions to construct step by step instead?
- // FIXME: maybe this isn't even needed anymore...
- path = BLI_sprintfN("material_slots[\"%s\"].material.texture_slots[\"%s\"].texture.%s",
- name_esc_ma, name_esc_tex, basepath);
-
- /* free old one */
- if (basepath != base_path)
- MEM_freeN(basepath);
- }
- break;
- }
- default:
- break;
- }
+ /* TODO: after material textures were removed, this function serves
+ * no purpose anymore, but could be used again so was not removed. */
/* fix RNA pointer, as we've now changed the ID root by changing the paths */
if (basepath != path) {
@@ -1173,6 +1161,9 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
/* grease pencil */
ANIMDATA_IDS_CB(bmain->gpencil.first);
+ /* palettes */
+ ANIMDATA_IDS_CB(bmain->palettes.first);
+
/* cache files */
ANIMDATA_IDS_CB(bmain->cachefiles.first);
}
@@ -1477,42 +1468,14 @@ void BKE_keyingsets_free(ListBase *list)
/* ***************************************** */
/* Evaluation Data-Setting Backend */
-/* Retrieve string to act as RNA-path, adjusted using mapping-table if provided
- * It returns whether the string needs to be freed (i.e. if it was a temp remapped one)
- * // FIXME: maybe it would be faster if we didn't have to alloc/free strings like this all the time, but for now it's safer
- *
- * - remap: remapping table to use
- * - path: original path string (as stored in F-Curve data)
- * - dst: destination string to write data to
- */
-static bool animsys_remap_path(AnimMapper *UNUSED(remap), char *path, char **dst)
-{
- /* is there a valid remapping table to use? */
-#if 0
- if (remap) {
- /* find a matching entry... to use to remap */
- /* ...TODO... */
- }
-#endif
-
- /* nothing suitable found, so just set dst to look at path (i.e. no alloc/free needed) */
- *dst = path;
- return false;
-}
-
static bool animsys_store_rna_setting(
- PointerRNA *ptr, AnimMapper *remap,
+ PointerRNA *ptr,
/* typically 'fcu->rna_path', 'fcu->array_index' */
const char *rna_path, const int array_index,
PathResolvedRNA *r_result)
{
bool success = false;
-
- char *path = NULL;
- bool free_path;
-
- /* get path, remapped as appropriate to work in its new environment */
- free_path = animsys_remap_path(remap, (char *)rna_path, &path);
+ const char *path = rna_path;
/* write value to setting */
if (path) {
@@ -1546,11 +1509,6 @@ static bool animsys_store_rna_setting(
}
}
- /* free temp path-info */
- if (free_path) {
- MEM_freeN((void *)path);
- }
-
return success;
}
@@ -1558,6 +1516,72 @@ static bool animsys_store_rna_setting(
/* less than 1.0 evaluates to false, use epsilon to avoid float error */
#define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON)))
+static bool animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value)
+{
+ PropertyRNA *prop = anim_rna->prop;
+ PointerRNA *ptr = &anim_rna->ptr;
+ int array_index = anim_rna->prop_index;
+ float orig_value;
+
+ /* caller must ensure this is animatable */
+ BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
+
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ {
+ if (array_index != -1) {
+ const int orig_value_coerce = RNA_property_boolean_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const int orig_value_coerce = RNA_property_boolean_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_INT:
+ {
+ if (array_index != -1) {
+ const int orig_value_coerce = RNA_property_int_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const int orig_value_coerce = RNA_property_int_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_FLOAT:
+ {
+ if (array_index != -1) {
+ const float orig_value_coerce = RNA_property_float_get_index(ptr, prop, array_index);
+ orig_value = (float)orig_value_coerce;
+ }
+ else {
+ const float orig_value_coerce = RNA_property_float_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ }
+ break;
+ }
+ case PROP_ENUM:
+ {
+ const int orig_value_coerce = RNA_property_enum_get(ptr, prop);
+ orig_value = (float)orig_value_coerce;
+ break;
+ }
+ default:
+ /* nothing can be done here... so it is unsuccessful? */
+ return false;
+ }
+
+ if (r_value != NULL) {
+ *r_value = orig_value;
+ }
+
+ /* successful */
+ return true;
+}
+
/* Write the given value to a setting using RNA, and return success */
static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value)
{
@@ -1568,27 +1592,24 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
/* caller must ensure this is animatable */
BLI_assert(RNA_property_animateable(ptr, prop) || ptr->id.data == NULL);
- /* set value for animatable numerical values only
- * HACK: some local F-Curves (e.g. those on NLA Strips) are evaluated
- * without an ID provided, which causes the animateable test to fail!
- */
- bool written = false;
+ /* Check whether value is new. Otherwise we skip all the updates. */
+ float old_value;
+ if (!animsys_read_rna_setting(anim_rna, &old_value)) {
+ return false;
+ }
+ if (old_value == value) {
+ return true;
+ }
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
{
const int value_coerce = ANIMSYS_FLOAT_AS_BOOL(value);
if (array_index != -1) {
- if (RNA_property_boolean_get_index(ptr, prop, array_index) != value_coerce) {
- RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
- written = true;
- }
+ RNA_property_boolean_set_index(ptr, prop, array_index, value_coerce);
}
else {
- if (RNA_property_boolean_get(ptr, prop) != value_coerce) {
- RNA_property_boolean_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_boolean_set(ptr, prop, value_coerce);
}
break;
}
@@ -1597,16 +1618,10 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
int value_coerce = (int)value;
RNA_property_int_clamp(ptr, prop, &value_coerce);
if (array_index != -1) {
- if (RNA_property_int_get_index(ptr, prop, array_index) != value_coerce) {
- RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
- written = true;
- }
+ RNA_property_int_set_index(ptr, prop, array_index, value_coerce);
}
else {
- if (RNA_property_int_get(ptr, prop) != value_coerce) {
- RNA_property_int_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_int_set(ptr, prop, value_coerce);
}
break;
}
@@ -1615,26 +1630,17 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
float value_coerce = value;
RNA_property_float_clamp(ptr, prop, &value_coerce);
if (array_index != -1) {
- if (RNA_property_float_get_index(ptr, prop, array_index) != value_coerce) {
- RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
- written = true;
- }
+ RNA_property_float_set_index(ptr, prop, array_index, value_coerce);
}
else {
- if (RNA_property_float_get(ptr, prop) != value_coerce) {
- RNA_property_float_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_float_set(ptr, prop, value_coerce);
}
break;
}
case PROP_ENUM:
{
const int value_coerce = (int)value;
- if (RNA_property_enum_get(ptr, prop) != value_coerce) {
- RNA_property_enum_set(ptr, prop, value_coerce);
- written = true;
- }
+ RNA_property_enum_set(ptr, prop, value_coerce);
break;
}
default:
@@ -1642,54 +1648,17 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val
return false;
}
- /* RNA property update disabled for now - [#28525] [#28690] [#28774] [#28777] */
-#if 0
- /* buffer property update for later flushing */
- if (written && RNA_property_update_check(prop)) {
- short skip_updates_hack = 0;
-
- /* optimization hacks: skip property updates for those properties
- * for we know that which the updates in RNA were really just for
- * flushing property editing via UI/Py
- */
- if (new_ptr.type == &RNA_PoseBone) {
- /* bone transforms - update pose (i.e. tag depsgraph) */
- skip_updates_hack = 1;
- }
-
- if (skip_updates_hack == 0)
- RNA_property_update_cache_add(ptr, prop);
- }
-#endif
-
- /* as long as we don't do property update, we still tag datablock
- * as having been updated. this flag does not cause any updates to
- * be run, it's for e.g. render engines to synchronize data */
- if (written && ptr->id.data) {
- ID *id = ptr->id.data;
-
- /* for cases like duplifarmes it's only a temporary so don't
- * notify anyone of updates */
- if (!(id->recalc & ID_RECALC_SKIP_ANIM_TAG)) {
- /* NOTE: This is a bit annoying to use atomic API here, but this
- * code is at it's EOL and removed already in 2.8 branch.
- */
- atomic_fetch_and_or_int32(&id->recalc, ID_RECALC);
- DAG_id_type_tag(G.main, GS(id->name));
- }
- }
-
/* successful */
return true;
}
/* Simple replacement based data-setting of the FCurve using RNA */
-bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu, float curval)
+bool BKE_animsys_execute_fcurve(PointerRNA *ptr, FCurve *fcu, float curval)
{
PathResolvedRNA anim_rna;
bool ok = false;
- if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
ok = animsys_write_rna_setting(&anim_rna, curval);
}
@@ -1697,24 +1666,53 @@ bool BKE_animsys_execute_fcurve(PointerRNA *ptr, AnimMapper *remap, FCurve *fcu,
return ok;
}
+static void animsys_write_orig_anim_rna(
+ PointerRNA *ptr,
+ const char *rna_path,
+ int array_index,
+ float value)
+{
+ /* Pointer is expected to be an ID pointer, if it's not -- we are doomed.
+ *
+ * NOTE: It is possible to have animation data on NLA strip, see T57360.
+ * TODO(sergey): Find solution for those cases.
+ */
+ if (ptr->id.data == NULL) {
+ return;
+ }
+ PointerRNA orig_ptr = *ptr;
+ orig_ptr.id.data = ((ID *)orig_ptr.id.data)->orig_id;
+ orig_ptr.data = orig_ptr.id.data;
+ PathResolvedRNA orig_anim_rna;
+ /* TODO(sergey): Is there a faster way to get anim_rna of original ID? */
+ if (animsys_store_rna_setting(&orig_ptr, rna_path, array_index, &orig_anim_rna)) {
+ animsys_write_rna_setting(&orig_anim_rna, value);
+ }
+}
+
/* Evaluate all the F-Curves in the given list
* This performs a set of standard checks. If extra checks are required, separate code should be used
*/
-static void animsys_evaluate_fcurves(PointerRNA *ptr, ListBase *list, AnimMapper *remap, float ctime)
-{
- FCurve *fcu;
-
- /* calculate then execute each curve */
- for (fcu = list->first; fcu; fcu = fcu->next) {
- /* check if this F-Curve doesn't belong to a muted group */
- if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED) == 0) {
- /* check if this curve should be skipped */
- if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
- PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
- const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
- animsys_write_rna_setting(&anim_rna, curval);
- }
+static void animsys_evaluate_fcurves(
+ Depsgraph *depsgraph, PointerRNA *ptr, ListBase *list, float ctime)
+{
+ const bool is_active_depsgraph = DEG_is_active(depsgraph);
+ /* Calculate then execute each curve. */
+ for (FCurve *fcu = list->first; fcu; fcu = fcu->next) {
+ /* Check if this F-Curve doesn't belong to a muted group. */
+ if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) {
+ continue;
+ }
+ /* Check if this curve should be skipped. */
+ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) {
+ continue;
+ }
+ PathResolvedRNA anim_rna;
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
+ animsys_write_rna_setting(&anim_rna, curval);
+ if (is_active_depsgraph) {
+ animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval);
}
}
}
@@ -1745,7 +1743,7 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, AnimData *adt, float ctime
* new to only be done when drivers only changed */
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
ok = animsys_write_rna_setting(&anim_rna, curval);
}
@@ -1798,13 +1796,12 @@ static void action_idcode_patch_check(ID *id, bAction *act)
/* ----------------------------------------- */
/* Evaluate Action Group */
-void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *agrp, AnimMapper *remap, float ctime)
+void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *agrp, float ctime)
{
FCurve *fcu;
/* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
if (ELEM(NULL, act, agrp)) return;
- if ((remap) && (remap->target != act)) remap = NULL;
action_idcode_patch_check(ptr->id.data, act);
@@ -1817,7 +1814,7 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, remap, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ if (animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, ctime);
animsys_write_rna_setting(&anim_rna, curval);
}
@@ -1826,16 +1823,21 @@ void animsys_evaluate_action_group(PointerRNA *ptr, bAction *act, bActionGroup *
}
/* Evaluate Action (F-Curve Bag) */
-void animsys_evaluate_action(PointerRNA *ptr, bAction *act, AnimMapper *remap, float ctime)
+static void animsys_evaluate_action_ex(
+ Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime)
{
/* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */
if (act == NULL) return;
- if ((remap) && (remap->target != act)) remap = NULL;
action_idcode_patch_check(ptr->id.data, act);
/* calculate then execute each curve */
- animsys_evaluate_fcurves(ptr, &act->curves, remap, ctime);
+ animsys_evaluate_fcurves(depsgraph, ptr, &act->curves, ctime);
+}
+
+void animsys_evaluate_action(Depsgraph *depsgraph, PointerRNA *ptr, bAction *act, float ctime)
+{
+ animsys_evaluate_action_ex(depsgraph, ptr, act, ctime);
}
/* ***************************************** */
@@ -1864,7 +1866,7 @@ static float nlastrip_get_influence(NlaStrip *strip, float cframe)
}
/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
-static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
+static void nlastrip_evaluate_controls(Depsgraph *depsgraph, NlaStrip *strip, float ctime)
{
/* now strip's evaluate F-Curves for these settings (if applicable) */
if (strip->fcurves.first) {
@@ -1874,7 +1876,7 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
/* execute these settings as per normal */
- animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime);
+ animsys_evaluate_fcurves(depsgraph, &strip_ptr, &strip->fcurves, ctime);
}
/* analytically generate values for influence and time (if applicable)
@@ -1896,7 +1898,7 @@ static void nlastrip_evaluate_controls(NlaStrip *strip, float ctime)
}
/* gets the strip active at the current time for a list of strips for evaluation purposes */
-NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime)
+NlaEvalStrip *nlastrips_ctime_get_strip(Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime)
{
NlaStrip *strip, *estrip = NULL;
NlaEvalStrip *nes;
@@ -1973,7 +1975,7 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short
* - negative influence is not supported yet... how would that be defined?
*/
/* TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... */
- nlastrip_evaluate_controls(estrip, ctime);
+ nlastrip_evaluate_controls(depsgraph, estrip, ctime);
if (estrip->influence <= 0.0f)
return NULL;
@@ -1992,8 +1994,8 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short
return NULL;
/* evaluate controls for the relevant extents of the bordering strips... */
- nlastrip_evaluate_controls(estrip->prev, estrip->start);
- nlastrip_evaluate_controls(estrip->next, estrip->end);
+ nlastrip_evaluate_controls(depsgraph, estrip->prev, estrip->start);
+ nlastrip_evaluate_controls(depsgraph, estrip->next, estrip->end);
break;
}
@@ -2016,7 +2018,7 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short
/* find an NlaEvalChannel that matches the given criteria
* - ptr and prop are the RNA data to find a match for
*/
-static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, PointerRNA *ptr, PropertyRNA *prop, int array_index)
+static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, const PathResolvedRNA *prna)
{
NlaEvalChannel *nec;
@@ -2031,7 +2033,7 @@ static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, PointerRNA *pt
* other data stored in PointerRNA cannot allow us to definitively
* identify the data
*/
- if ((nec->ptr.data == ptr->data) && (nec->prop == prop) && (nec->index == array_index))
+ if ((nec->rna.ptr.data == prna->ptr.data) && (nec->rna.prop == prna->prop) && ELEM(nec->rna.prop_index, -1, prna->prop_index))
return nec;
}
@@ -2040,11 +2042,11 @@ static NlaEvalChannel *nlaevalchan_find_match(ListBase *channels, PointerRNA *pt
}
/* initialise default value for NlaEvalChannel, so that it doesn't blend things wrong */
-static void nlaevalchan_value_init(NlaEvalChannel *nec)
+static float nlaevalchan_init_value(PathResolvedRNA *rna)
{
- PointerRNA *ptr = &nec->ptr;
- PropertyRNA *prop = nec->prop;
- int index = nec->index;
+ PointerRNA *ptr = &rna->ptr;
+ PropertyRNA *prop = rna->prop;
+ int index = rna->prop_index;
/* NOTE: while this doesn't work for all RNA properties as default values aren't in fact
* set properly for most of them, at least the common ones (which also happen to get used
@@ -2053,61 +2055,43 @@ static void nlaevalchan_value_init(NlaEvalChannel *nec)
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
if (RNA_property_array_check(prop))
- nec->value = (float)RNA_property_boolean_get_default_index(ptr, prop, index);
+ return (float)RNA_property_boolean_get_default_index(ptr, prop, index);
else
- nec->value = (float)RNA_property_boolean_get_default(ptr, prop);
- break;
+ return (float)RNA_property_boolean_get_default(ptr, prop);
case PROP_INT:
if (RNA_property_array_check(prop))
- nec->value = (float)RNA_property_int_get_default_index(ptr, prop, index);
+ return (float)RNA_property_int_get_default_index(ptr, prop, index);
else
- nec->value = (float)RNA_property_int_get_default(ptr, prop);
- break;
+ return (float)RNA_property_int_get_default(ptr, prop);
case PROP_FLOAT:
if (RNA_property_array_check(prop))
- nec->value = RNA_property_float_get_default_index(ptr, prop, index);
+ return RNA_property_float_get_default_index(ptr, prop, index);
else
- nec->value = RNA_property_float_get_default(ptr, prop);
- break;
+ return RNA_property_float_get_default(ptr, prop);
case PROP_ENUM:
- nec->value = (float)RNA_property_enum_get_default(ptr, prop);
- break;
+ return (float)RNA_property_enum_get_default(ptr, prop);
default:
- break;
+ return 0.0f;
}
}
/* verify that an appropriate NlaEvalChannel for this F-Curve exists */
-static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, bool *newChan)
+static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, FCurve *fcu, bool *newChan)
{
NlaEvalChannel *nec;
- NlaStrip *strip = nes->strip;
- PropertyRNA *prop;
- PointerRNA new_ptr;
- char *path = NULL;
- /* short free_path = 0; */
+ PathResolvedRNA rna;
/* sanity checks */
if (channels == NULL)
return NULL;
/* get RNA pointer+property info from F-Curve for more convenient handling */
- /* get path, remapped as appropriate to work in its new environment */
- /* free_path = */ /* UNUSED */ animsys_remap_path(strip->remap, fcu->rna_path, &path);
-
- /* a valid property must be available, and it must be animatable */
- if (RNA_path_resolve_property(ptr, path, &new_ptr, &prop) == false) {
- if (G.debug & G_DEBUG) printf("NLA Strip Eval: Cannot resolve path\n");
- return NULL;
- }
- /* only ok if animatable */
- else if (RNA_property_animateable(&new_ptr, prop) == 0) {
- if (G.debug & G_DEBUG) printf("NLA Strip Eval: Property not animatable\n");
+ if (!animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &rna)) {
return NULL;
}
/* try to find a match */
- nec = nlaevalchan_find_match(channels, &new_ptr, prop, fcu->array_index);
+ nec = nlaevalchan_find_match(channels, &rna);
/* allocate a new struct for this if none found */
if (nec == NULL) {
@@ -2115,12 +2099,13 @@ static NlaEvalChannel *nlaevalchan_verify(PointerRNA *ptr, ListBase *channels, N
BLI_addtail(channels, nec);
/* store property links for writing to the property later */
- nec->ptr = new_ptr;
- nec->prop = prop;
- nec->index = fcu->array_index;
+ nec->rna = rna;
+
+ /* store parameters for use with write_orig_anim_rna */
+ nec->rna_path = fcu->rna_path;
/* initialise value using default value of property [#35856] */
- nlaevalchan_value_init(nec);
+ nec->value = nlaevalchan_init_value(&rna);
*newChan = true;
}
else
@@ -2199,7 +2184,7 @@ static void nlaevalchan_buffers_accumulate(ListBase *channels, ListBase *tmp_buf
necn = nec->next;
/* try to find an existing matching channel for this setting in the accumulation buffer */
- necd = nlaevalchan_find_match(channels, &nec->ptr, nec->prop, nec->index);
+ necd = nlaevalchan_find_match(channels, &nec->rna);
/* if there was a matching channel already in the buffer, accumulate to it,
* otherwise, add the current channel to the buffer for efficiency
@@ -2326,7 +2311,7 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, ListBase *channels, Li
/* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s)
* stored in this channel if it has been used already
*/
- nec = nlaevalchan_verify(ptr, channels, nes, fcu, &newChan);
+ nec = nlaevalchan_verify(ptr, channels, fcu, &newChan);
if (nec)
nlaevalchan_accumulate(nec, nes, value, newChan);
}
@@ -2339,7 +2324,8 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr, ListBase *channels, Li
}
/* evaluate transition strip */
-static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+static void nlastrip_evaluate_transition(
+ Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
ListBase tmp_channels = {NULL, NULL};
ListBase tmp_modifiers = {NULL, NULL};
@@ -2379,12 +2365,12 @@ static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, Li
/* first strip */
tmp_nes.strip_mode = NES_TIME_TRANSITION_START;
tmp_nes.strip = s1;
- nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
+ nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
/* second strip */
tmp_nes.strip_mode = NES_TIME_TRANSITION_END;
tmp_nes.strip = s2;
- nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
+ nlastrip_evaluate(depsgraph, ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
/* accumulate temp-buffer and full-buffer, using the 'real' strip */
@@ -2395,7 +2381,8 @@ static void nlastrip_evaluate_transition(PointerRNA *ptr, ListBase *channels, Li
}
/* evaluate meta-strip */
-static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+static void nlastrip_evaluate_meta(
+ Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
ListBase tmp_modifiers = {NULL, NULL};
NlaStrip *strip = nes->strip;
@@ -2415,13 +2402,13 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase
/* find the child-strip to evaluate */
evaltime = (nes->strip_time * (strip->end - strip->start)) + strip->start;
- tmp_nes = nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime);
+ tmp_nes = nlastrips_ctime_get_strip(depsgraph, NULL, &strip->strips, -1, evaltime);
/* directly evaluate child strip into accumulation buffer...
* - there's no need to use a temporary buffer (as it causes issues [T40082])
*/
if (tmp_nes) {
- nlastrip_evaluate(ptr, channels, &tmp_modifiers, tmp_nes);
+ nlastrip_evaluate(depsgraph, ptr, channels, &tmp_modifiers, tmp_nes);
/* free temp eval-strip */
MEM_freeN(tmp_nes);
@@ -2432,7 +2419,7 @@ static void nlastrip_evaluate_meta(PointerRNA *ptr, ListBase *channels, ListBase
}
/* evaluates the given evaluation strip */
-void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
+void nlastrip_evaluate(Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
NlaStrip *strip = nes->strip;
@@ -2450,10 +2437,10 @@ void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers,
nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes);
break;
case NLASTRIP_TYPE_TRANSITION: /* transition */
- nlastrip_evaluate_transition(ptr, channels, modifiers, nes);
+ nlastrip_evaluate_transition(depsgraph, ptr, channels, modifiers, nes);
break;
case NLASTRIP_TYPE_META: /* meta */
- nlastrip_evaluate_meta(ptr, channels, modifiers, nes);
+ nlastrip_evaluate_meta(depsgraph, ptr, channels, modifiers, nes);
break;
default: /* do nothing */
@@ -2465,7 +2452,7 @@ void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers,
}
/* write the accumulated settings to */
-void nladata_flush_channels(ListBase *channels)
+void nladata_flush_channels(Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels)
{
NlaEvalChannel *nec;
@@ -2473,39 +2460,13 @@ void nladata_flush_channels(ListBase *channels)
if (channels == NULL)
return;
+ const bool is_active_depsgraph = DEG_is_active(depsgraph);
+
/* for each channel with accumulated values, write its value on the property it affects */
for (nec = channels->first; nec; nec = nec->next) {
- PointerRNA *ptr = &nec->ptr;
- PropertyRNA *prop = nec->prop;
- int array_index = nec->index;
- float value = nec->value;
-
- /* write values - see animsys_write_rna_setting() to sync the code */
- switch (RNA_property_type(prop)) {
- case PROP_BOOLEAN:
- if (RNA_property_array_check(prop))
- RNA_property_boolean_set_index(ptr, prop, array_index, ANIMSYS_FLOAT_AS_BOOL(value));
- else
- RNA_property_boolean_set(ptr, prop, ANIMSYS_FLOAT_AS_BOOL(value));
- break;
- case PROP_INT:
- if (RNA_property_array_check(prop))
- RNA_property_int_set_index(ptr, prop, array_index, (int)value);
- else
- RNA_property_int_set(ptr, prop, (int)value);
- break;
- case PROP_FLOAT:
- if (RNA_property_array_check(prop))
- RNA_property_float_set_index(ptr, prop, array_index, value);
- else
- RNA_property_float_set(ptr, prop, value);
- break;
- case PROP_ENUM:
- RNA_property_enum_set(ptr, prop, (int)value);
- break;
- default:
- /* can't do anything with other types of property.... */
- break;
+ animsys_write_rna_setting(&nec->rna, nec->value);
+ if (is_active_depsgraph) {
+ animsys_write_orig_anim_rna(ptr, nec->rna_path, nec->rna.prop_index, nec->value);
}
}
}
@@ -2519,7 +2480,7 @@ void nladata_flush_channels(ListBase *channels)
*
* \param[out] echannels Evaluation channels with calculated values
*/
-static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime)
+static void animsys_evaluate_nla(Depsgraph *depsgraph, ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime)
{
NlaTrack *nlt;
short track_index = 0;
@@ -2557,7 +2518,7 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
has_strips = true;
/* otherwise, get strip to evaluate for this channel */
- nes = nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime);
+ nes = nlastrips_ctime_get_strip(depsgraph, &estrips, &nlt->strips, track_index, ctime);
if (nes) nes->track = nlt;
}
@@ -2582,7 +2543,6 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
else {
/* set settings of dummy NLA strip from AnimData settings */
dummy_strip.act = adt->action;
- dummy_strip.remap = adt->remap;
/* action range is calculated taking F-Modifiers into account (which making new strips doesn't do due to the troublesome nature of that) */
calc_action_range(dummy_strip.act, &dummy_strip.actstart, &dummy_strip.actend, 1);
@@ -2598,14 +2558,14 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
}
/* add this to our list of evaluation strips */
- nlastrips_ctime_get_strip(&estrips, &dummy_trackslist, -1, ctime);
+ nlastrips_ctime_get_strip(depsgraph, &estrips, &dummy_trackslist, -1, ctime);
}
else {
/* special case - evaluate as if there isn't any NLA data */
/* TODO: this is really just a stop-gap measure... */
if (G.debug & G_DEBUG) printf("NLA Eval: Stopgap for active action on NLA Stack - no strips case\n");
- animsys_evaluate_action(ptr, adt->action, adt->remap, ctime);
+ animsys_evaluate_action(depsgraph, ptr, adt->action, ctime);
BLI_freelistN(&estrips);
return;
}
@@ -2618,28 +2578,17 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
/* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
for (nes = estrips.first; nes; nes = nes->next)
- nlastrip_evaluate(ptr, echannels, NULL, nes);
+ nlastrip_evaluate(depsgraph, ptr, echannels, NULL, nes);
/* 3. free temporary evaluation data that's not used elsewhere */
BLI_freelistN(&estrips);
-
- /* Tag ID as updated so render engines will recognize changes in data
- * which is animated but doesn't have actions.
- */
- if (ptr->id.data != NULL) {
- ID *id = ptr->id.data;
- if (!(id->recalc & ID_RECALC_SKIP_ANIM_TAG)) {
- id->recalc |= ID_RECALC;
- DAG_id_type_tag(G.main, GS(id->name));
- }
- }
}
/* NLA Evaluation function (mostly for use through do_animdata)
* - All channels that will be affected are not cleared anymore. Instead, we just evaluate into
* some temp channels, where values can be accumulated in one go.
*/
-static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime)
+static void animsys_calculate_nla(Depsgraph *depsgraph, PointerRNA *ptr, AnimData *adt, float ctime)
{
ListBase echannels = {NULL, NULL};
@@ -2647,10 +2596,10 @@ static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime)
* and also when the user jumps between different times instead of moving sequentially... */
/* evaluate the NLA stack, obtaining a set of values to flush */
- animsys_evaluate_nla(&echannels, ptr, adt, ctime);
+ animsys_evaluate_nla(depsgraph, &echannels, ptr, adt, ctime);
/* flush effects of accumulating channels in NLA to the actual data they affect */
- nladata_flush_channels(&echannels);
+ nladata_flush_channels(depsgraph, ptr, &echannels);
/* free temp data */
BLI_freelistN(&echannels);
@@ -2659,19 +2608,6 @@ static void animsys_calculate_nla(PointerRNA *ptr, AnimData *adt, float ctime)
/* ***************************************** */
/* Overrides System - Public API */
-/* Clear all overrides */
-
-/* Add or get existing Override for given setting */
-#if 0
-AnimOverride *BKE_animsys_validate_override(PointerRNA *UNUSED(ptr), char *UNUSED(path), int UNUSED(array_index))
-{
- /* FIXME: need to define how to get overrides */
- return NULL;
-}
-#endif
-
-/* -------------------- */
-
/* Evaluate Overrides */
static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
{
@@ -2680,7 +2616,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
/* for each override, simply execute... */
for (aor = adt->overrides.first; aor; aor = aor->next) {
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(ptr, NULL, aor->rna_path, aor->array_index, &anim_rna)) {
+ if (animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) {
animsys_write_rna_setting(&anim_rna, aor->value);
}
}
@@ -2726,7 +2662,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
* and that the flags for which parts of the anim-data settings need to be recalculated
* have been set already by the depsgraph. Now, we use the recalc
*/
-void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
+void BKE_animsys_evaluate_animdata(Depsgraph *depsgraph, Scene *scene, ID *id, AnimData *adt, float ctime, short recalc)
{
PointerRNA id_ptr;
@@ -2748,11 +2684,11 @@ void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ct
/* evaluate NLA-stack
* - active action is evaluated as part of the NLA stack as the last item
*/
- animsys_calculate_nla(&id_ptr, adt, ctime);
+ animsys_calculate_nla(depsgraph, &id_ptr, adt, ctime);
}
/* evaluate Active Action only */
else if (adt->action)
- animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime);
+ animsys_evaluate_action_ex(depsgraph, &id_ptr, adt->action, ctime);
/* reset tag */
adt->recalc &= ~ADT_RECALC_ANIM;
@@ -2796,7 +2732,7 @@ void BKE_animsys_evaluate_animdata(Scene *scene, ID *id, AnimData *adt, float ct
* 'local' (i.e. belonging in the nearest ID-block that setting is related to, not a
* standard 'root') block are overridden by a larger 'user'
*/
-void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
+void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene *scene, float ctime)
{
ID *id;
@@ -2812,7 +2748,7 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
for (id = first; id; id = id->next) { \
if (ID_REAL_USERS(id) > 0) { \
AnimData *adt = BKE_animdata_from_id(id); \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
} \
} (void)0
@@ -2829,9 +2765,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
NtId_Type *ntp = (NtId_Type *)id; \
if (ntp->nodetree) { \
AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
- BKE_animsys_evaluate_animdata(scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, (ID *)ntp->nodetree, adt2, ctime, ADT_RECALC_ANIM); \
} \
- BKE_animsys_evaluate_animdata(scene, id, adt, ctime, aflag); \
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, aflag); \
} \
} (void)0
@@ -2898,6 +2834,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* grease pencil */
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
+ /* palettes */
+ EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM);
+
/* cache files */
EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
@@ -2923,27 +2862,60 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* ************** */
/* Evaluation API */
-void BKE_animsys_eval_animdata(EvaluationContext *eval_ctx, ID *id)
+void BKE_animsys_eval_animdata(Depsgraph *depsgraph, ID *id)
{
+ float ctime = DEG_get_ctime(depsgraph);
AnimData *adt = BKE_animdata_from_id(id);
Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates,
* which should get handled as part of the dependency graph instead...
*/
- DEG_debug_print_eval_time(__func__, id->name, id, eval_ctx->ctime);
- BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM);
+ DEG_debug_print_eval_time(depsgraph, __func__, id->name, id, ctime);
+ short recalc = ADT_RECALC_ANIM;
+ BKE_animsys_evaluate_animdata(depsgraph, scene, id, adt, ctime, recalc);
}
-void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
+void BKE_animsys_update_driver_array(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ /* Runtime driver map to avoid O(n^2) lookups in BKE_animsys_eval_driver.
+ * Ideally the depsgraph could pass a pointer to the COW driver directly,
+ * but this is difficult in the current design. */
+ if (adt && adt->drivers.first) {
+ BLI_assert(!adt->driver_array);
+
+ int num_drivers = BLI_listbase_count(&adt->drivers);
+ adt->driver_array = MEM_mallocN(sizeof(FCurve *) * num_drivers, "adt->driver_array");
+
+ int driver_index = 0;
+ for (FCurve *fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ adt->driver_array[driver_index++] = fcu;
+ }
+ }
+}
+
+void BKE_animsys_eval_driver(Depsgraph *depsgraph,
ID *id,
- FCurve *fcu)
+ int driver_index,
+ ChannelDriver *driver_orig)
{
/* TODO(sergey): De-duplicate with BKE animsys. */
- ChannelDriver *driver = fcu->driver;
PointerRNA id_ptr;
bool ok = false;
+ /* Lookup driver, accelerated with driver array map. */
+ const AnimData *adt = BKE_animdata_from_id(id);
+ FCurve *fcu;
+
+ if (adt->driver_array) {
+ fcu = adt->driver_array[driver_index];
+ }
+ else {
+ fcu = BLI_findlink(&adt->drivers, driver_index);
+ }
+
DEG_debug_print_eval_subdata_index(
- __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
+ depsgraph, __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index);
RNA_id_pointer_create(id, &id_ptr);
@@ -2951,27 +2923,31 @@ void BKE_animsys_eval_driver(EvaluationContext *eval_ctx,
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0) {
/* check if driver itself is tagged for recalculation */
/* XXX driver recalc flag is not set yet by depsgraph! */
- if ((driver) && !(driver->flag & DRIVER_FLAG_INVALID) /*&& (driver->flag & DRIVER_FLAG_RECALC)*/) {
+ if ((driver_orig) && !(driver_orig->flag & DRIVER_FLAG_INVALID) /*&& (driver_orig->flag & DRIVER_FLAG_RECALC)*/) {
/* evaluate this using values set already in other places
* NOTE: for 'layering' option later on, we should check if we should remove old value before adding
* new to only be done when drivers only changed */
//printf("\told val = %f\n", fcu->curval);
PathResolvedRNA anim_rna;
- if (animsys_store_rna_setting(&id_ptr, NULL, fcu->rna_path, fcu->array_index, &anim_rna)) {
- const float curval = calculate_fcurve(&anim_rna, fcu, eval_ctx->ctime);
+ if (animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
+ const float ctime = DEG_get_ctime(depsgraph);
+ const float curval = evaluate_fcurve_driver(&anim_rna, fcu, driver_orig, ctime);
ok = animsys_write_rna_setting(&anim_rna, curval);
+ if (ok && DEG_is_active(depsgraph)) {
+ animsys_write_orig_anim_rna(&id_ptr, fcu->rna_path, fcu->array_index, curval);
+ }
}
//printf("\tnew val = %f\n", fcu->curval);
/* clear recalc flag */
- driver->flag &= ~DRIVER_FLAG_RECALC;
+ driver_orig->flag &= ~DRIVER_FLAG_RECALC;
/* set error-flag if evaluation failed */
if (ok == 0) {
printf("invalid driver - %s[%d]\n", fcu->rna_path, fcu->array_index);
- driver->flag |= DRIVER_FLAG_INVALID;
+ driver_orig->flag |= DRIVER_FLAG_INVALID;
}
}
}
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 8d6c34222d7..2848c245553 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -28,9 +28,11 @@
#include <stdio.h>
#include "BLI_utildefines.h"
-#include "BLI_string.h"
#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_listbase.h"
#include "BLI_path_util.h"
+#include "BLI_string.h"
#include "BKE_blender_version.h"
#include "BKE_appdir.h" /* own include */
@@ -738,6 +740,32 @@ bool BKE_appdir_app_template_id_search(const char *app_template, char *path, siz
return false;
}
+void BKE_appdir_app_templates(ListBase *templates)
+{
+ BLI_listbase_clear(templates);
+
+ for (int i = 0; i < 2; i++) {
+ char subdir[FILE_MAX];
+ if (!BKE_appdir_folder_id_ex(
+ app_template_directory_id[i], app_template_directory_search[i],
+ subdir, sizeof(subdir)))
+ {
+ continue;
+ }
+
+ struct direntry *dir;
+ uint totfile = BLI_filelist_dir_contents(subdir, &dir);
+ for (int f = 0; f < totfile; f++) {
+ if (!FILENAME_IS_CURRPAR(dir[f].relname) && S_ISDIR(dir[f].type)) {
+ char *template = BLI_strdup(dir[f].relname);
+ BLI_addtail(templates, BLI_genericNodeN(template));
+ }
+ }
+
+ BLI_filelist_free(dir, totfile);
+ }
+}
+
/**
* Gets the temp directory when blender first runs.
* If the default path is not found, use try $TEMP
@@ -813,7 +841,9 @@ static void where_is_temp(char *fullname, char *basename, const size_t maxlen, c
BLI_dir_create_recursive(tmp_name);
}
#else
- mkdtemp(tmp_name);
+ if (mkdtemp(tmp_name) == NULL) {
+ BLI_dir_create_recursive(tmp_name);
+ }
#endif
}
if (BLI_is_dir(tmp_name)) {
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 2eded2ee8f1..fa5b59b739d 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -27,7 +27,6 @@
* \ingroup bke
*/
-
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
@@ -47,6 +46,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_mesh_types.h"
#include "DNA_lattice_types.h"
#include "DNA_listBase.h"
@@ -60,8 +60,6 @@
#include "BKE_anim.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_idprop.h"
@@ -73,8 +71,9 @@
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph_build.h"
+
#include "BIK_api.h"
-#include "BKE_sketch.h"
/* **************** Generic Functions, data level *************** */
@@ -136,12 +135,6 @@ void BKE_armature_free(bArmature *arm)
MEM_freeN(arm->edbo);
arm->edbo = NULL;
}
-
- /* free sketch */
- if (arm->sketch) {
- freeSketch(arm->sketch);
- arm->sketch = NULL;
- }
}
void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local)
@@ -205,7 +198,6 @@ void BKE_armature_copy_data(Main *UNUSED(bmain), bArmature *arm_dst, const bArma
arm_dst->edbo = NULL;
arm_dst->act_edbone = NULL;
- arm_dst->sketch = NULL;
}
bArmature *BKE_armature_copy(Main *bmain, const bArmature *arm)
@@ -401,7 +393,7 @@ int bone_autoside_name(char name[MAXBONENAME], int UNUSED(strip_number), short a
/* ************* B-Bone support ******************* */
/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
-void equalize_bbone_bezier(float *data, int desired)
+static void equalize_bbone_bezier(float *data, int desired)
{
float *fp, totdist, ddist, dist, fac1, fac2;
float pdist[MAX_BBONE_SUBDIV + 1];
@@ -441,169 +433,276 @@ void equalize_bbone_bezier(float *data, int desired)
copy_qt_qt(fp, temp[MAX_BBONE_SUBDIV]);
}
-/* returns pointer to static array, filled with desired amount of bone->segments elements */
-/* this calculation is done within unit bone space */
-void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BBONE_SUBDIV])
+/* Get "next" and "prev" bones - these are used for handle calculations. */
+void BKE_pchan_get_bbone_handles(bPoseChannel *pchan, bPoseChannel **r_prev, bPoseChannel **r_next)
+{
+ if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO) {
+ /* Use connected parent. */
+ if (pchan->bone->flag & BONE_CONNECTED) {
+ *r_prev = pchan->parent;
+ }
+ else {
+ *r_prev = NULL;
+ }
+ }
+ else {
+ /* Use the provided bone as prev - leave blank to eliminate this effect altogether. */
+ *r_prev = pchan->bbone_prev;
+ }
+
+ if (pchan->bone->bbone_next_type == BBONE_HANDLE_AUTO) {
+ /* Use connected child. */
+ *r_next = pchan->child;
+ }
+ else {
+ /* Use the provided bone as next - leave blank to eliminate this effect altogether. */
+ *r_next = pchan->bbone_next;
+ }
+}
+
+/* Fills the array with the desired amount of bone->segments elements.
+ * This calculation is done within unit bone space. */
+void b_bone_spline_setup(bPoseChannel *pchan, const bool rest, Mat4 result_array[MAX_BBONE_SUBDIV])
{
bPoseChannel *next, *prev;
Bone *bone = pchan->bone;
- float h1[3], h2[3], scale[3], length, roll1 = 0.0f, roll2;
- float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
- float data[MAX_BBONE_SUBDIV + 1][4], *fp;
- int a;
- bool do_scale = false;
+ BBoneSplineParameters param;
+ float imat[4][4], posemat[4][4];
+ float delta[3];
+
+ memset(&param, 0, sizeof(param));
- length = bone->length;
+ param.segments = bone->segments;
+ param.length = bone->length;
if (!rest) {
- /* check if we need to take non-uniform bone scaling into account */
+ float scale[3];
+
+ /* Check if we need to take non-uniform bone scaling into account. */
mat4_to_size(scale, pchan->pose_mat);
if (fabsf(scale[0] - scale[1]) > 1e-6f || fabsf(scale[1] - scale[2]) > 1e-6f) {
- size_to_mat4(scalemat, scale);
- invert_m4_m4(iscalemat, scalemat);
-
- length *= scale[1];
- do_scale = 1;
+ param.do_scale = true;
+ copy_v3_v3(param.scale, scale);
}
}
- /* get "next" and "prev" bones - these are used for handle calculations */
- if (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) {
- /* use the provided bones as the next/prev - leave blank to eliminate this effect altogether */
- prev = pchan->bbone_prev;
- next = pchan->bbone_next;
- }
- else {
- /* evaluate next and prev bones */
- if (bone->flag & BONE_CONNECTED)
- prev = pchan->parent;
- else
- prev = NULL;
-
- next = pchan->child;
- }
+ BKE_pchan_get_bbone_handles(pchan, &prev, &next);
- /* find the handle points, since this is inside bone space, the
+ /* Find the handle points, since this is inside bone space, the
* first point = (0, 0, 0)
* last point = (0, length, 0) */
if (rest) {
invert_m4_m4(imat, pchan->bone->arm_mat);
}
- else if (do_scale) {
+ else if (param.do_scale) {
copy_m4_m4(posemat, pchan->pose_mat);
normalize_m4(posemat);
invert_m4_m4(imat, posemat);
}
- else
+ else {
invert_m4_m4(imat, pchan->pose_mat);
+ }
if (prev) {
- float difmat[4][4], result[3][3], imat3[3][3];
+ float h1[3];
+ bool done = false;
- /* transform previous point inside this bone space */
- if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
- (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL))
- {
- /* Use delta movement (from restpose), and apply this relative to the current bone's head */
+ param.use_prev = true;
+
+ /* Transform previous point inside this bone space. */
+ if (bone->bbone_prev_type == BBONE_HANDLE_RELATIVE) {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's head. */
if (rest) {
- /* in restpose, arm_head == pose_head */
- h1[0] = h1[1] = h1[2] = 0.0f;
+ /* In restpose, arm_head == pose_head */
+ zero_v3(param.prev_h);
+ done = true;
}
else {
- float delta[3];
sub_v3_v3v3(delta, prev->pose_head, prev->bone->arm_head);
sub_v3_v3v3(h1, pchan->pose_head, delta);
}
}
- else {
- /* Use bone head as absolute position */
- if (rest)
- copy_v3_v3(h1, prev->bone->arm_head);
- else
- copy_v3_v3(h1, prev->pose_head);
+ else if (bone->bbone_prev_type == BBONE_HANDLE_TANGENT) {
+ /* Use bone direction by offsetting so that its tail meets current bone's head */
+ if (rest) {
+ sub_v3_v3v3(delta, prev->bone->arm_tail, prev->bone->arm_head);
+ sub_v3_v3v3(h1, bone->arm_head, delta);
+ }
+ else {
+ sub_v3_v3v3(delta, prev->pose_tail, prev->pose_head);
+ sub_v3_v3v3(h1, pchan->pose_head, delta);
+ }
}
- mul_m4_v3(imat, h1);
+ else {
+ /* Apply special handling for smoothly joining B-Bone chains */
+ param.prev_bbone = (prev->bone->segments > 1);
- if (prev->bone->segments > 1) {
- /* if previous bone is B-bone too, use average handle direction */
- h1[1] -= length;
- roll1 = 0.0f;
+ /* Use bone head as absolute position. */
+ copy_v3_v3(h1, rest ? prev->bone->arm_head : prev->pose_head);
}
- normalize_v3(h1);
- negate_v3(h1);
-
- if (prev->bone->segments == 1) {
- /* find the previous roll to interpolate */
- if (rest)
- mul_m4_m4m4(difmat, imat, prev->bone->arm_mat);
- else
- mul_m4_m4m4(difmat, imat, prev->pose_mat);
- copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */
-
- vec_roll_to_mat3(h1, 0.0f, mat3); /* the result of vec_roll without roll */
-
- invert_m3_m3(imat3, mat3);
- mul_m3_m3m3(mat3, result, imat3); /* the matrix transforming vec_roll to desired roll */
+ if (!done) {
+ mul_v3_m4v3(param.prev_h, imat, h1);
+ }
- roll1 = atan2f(mat3[2][0], mat3[2][2]);
+ if (!param.prev_bbone) {
+ /* Find the previous roll to interpolate. */
+ mul_m4_m4m4(param.prev_mat, imat, rest ? prev->bone->arm_mat : prev->pose_mat);
}
}
- else {
- h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
- roll1 = 0.0f;
- }
+
if (next) {
- float difmat[4][4], result[3][3], imat3[3][3];
+ float h2[3];
+ bool done = false;
- /* transform next point inside this bone space */
- if ((pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES) &&
- (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL))
- {
- /* Use delta movement (from restpose), and apply this relative to the current bone's tail */
+ param.use_next = true;
+
+ /* Transform next point inside this bone space. */
+ if (bone->bbone_next_type == BBONE_HANDLE_RELATIVE) {
+ /* Use delta movement (from restpose), and apply this relative to the current bone's tail. */
+ if (rest) {
+ /* In restpose, arm_head == pose_head */
+ copy_v3_fl3(param.next_h, 0.0f, param.length, 0.0);
+ done = true;
+ }
+ else {
+ sub_v3_v3v3(delta, next->pose_head, next->bone->arm_head);
+ add_v3_v3v3(h2, pchan->pose_tail, delta);
+ }
+ }
+ else if (bone->bbone_next_type == BBONE_HANDLE_TANGENT) {
+ /* Use bone direction by offsetting so that its head meets current bone's tail */
if (rest) {
- /* in restpose, arm_tail == pose_tail */
- h2[0] = h2[1] = h2[2] = 0.0f;
+ sub_v3_v3v3(delta, next->bone->arm_tail, next->bone->arm_head);
+ add_v3_v3v3(h2, bone->arm_tail, delta);
}
else {
- float delta[3];
- sub_v3_v3v3(delta, next->pose_tail, next->bone->arm_tail);
+ sub_v3_v3v3(delta, next->pose_tail, next->pose_head);
add_v3_v3v3(h2, pchan->pose_tail, delta);
}
}
else {
- /* Use bone tail as absolute position */
- if (rest)
- copy_v3_v3(h2, next->bone->arm_tail);
- else
- copy_v3_v3(h2, next->pose_tail);
+ /* Apply special handling for smoothly joining B-Bone chains */
+ param.next_bbone = (next->bone->segments > 1);
+
+ /* Use bone tail as absolute position. */
+ copy_v3_v3(h2, rest ? next->bone->arm_tail : next->pose_tail);
}
- mul_m4_v3(imat, h2);
- /* if next bone is B-bone too, use average handle direction */
- if (next->bone->segments > 1) {
- /* pass */
+ if (!done) {
+ mul_v3_m4v3(param.next_h, imat, h2);
}
- else {
- h2[1] -= length;
+
+ /* Find the next roll to interpolate as well. */
+ mul_m4_m4m4(param.next_mat, imat, rest ? next->bone->arm_mat : next->pose_mat);
+ }
+
+ /* Add effects from bbone properties over the top
+ * - These properties allow users to hand-animate the
+ * bone curve/shape, without having to resort to using
+ * extra bones
+ * - The "bone" level offsets are for defining the restpose
+ * shape of the bone (e.g. for curved eyebrows for example).
+ * -> In the viewport, it's needed to define what the rest pose
+ * looks like
+ * -> For "rest == 0", we also still need to have it present
+ * so that we can "cancel out" this restpose when it comes
+ * time to deform some geometry, it won't cause double transforms.
+ * - The "pchan" level offsets are the ones that animators actually
+ * end up animating
+ */
+ {
+ param.ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f);
+ param.ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f);
+
+ param.roll1 = bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
+ param.roll2 = bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
+
+ if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
+ if (prev) {
+ if (prev->bone) {
+ param.roll1 += prev->bone->roll2;
+ }
+
+ if (!rest) {
+ param.roll1 += prev->roll2;
+ }
+ }
}
- normalize_v3(h2);
- /* find the next roll to interpolate as well */
- if (rest)
- mul_m4_m4m4(difmat, imat, next->bone->arm_mat);
- else
- mul_m4_m4m4(difmat, imat, next->pose_mat);
- copy_m3_m4(result, difmat); /* the desired rotation at beginning of next bone */
+ param.scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ param.scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
- vec_roll_to_mat3(h2, 0.0f, mat3); /* the result of vec_roll without roll */
+ /* Extra curve x / y */
+ param.curveInX = bone->curveInX + (!rest ? pchan->curveInX : 0.0f);
+ param.curveInY = bone->curveInY + (!rest ? pchan->curveInY : 0.0f);
- invert_m3_m3(imat3, mat3);
- mul_m3_m3m3(mat3, imat3, result); /* the matrix transforming vec_roll to desired roll */
+ param.curveOutX = bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f);
+ param.curveOutY = bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f);
+ }
- roll2 = atan2f(mat3[2][0], mat3[2][2]);
+ bone->segments = BKE_compute_b_bone_spline(&param, result_array);
+}
+/* Fills the array with the desired amount of bone->segments elements.
+ * This calculation is done within unit bone space. */
+int BKE_compute_b_bone_spline(BBoneSplineParameters *param, Mat4 result_array[MAX_BBONE_SUBDIV])
+{
+ float scalemat[4][4], iscalemat[4][4];
+ float mat3[3][3];
+ float h1[3], roll1, h2[3], roll2;
+ float data[MAX_BBONE_SUBDIV + 1][4], *fp;
+ int a;
+
+ float length = param->length;
+
+ if (param->do_scale) {
+ size_to_mat4(scalemat, param->scale);
+ invert_m4_m4(iscalemat, scalemat);
+
+ length *= param->scale[1];
+ }
+
+ if (param->use_prev) {
+ copy_v3_v3(h1, param->prev_h);
+
+ if (param->prev_bbone) {
+ /* If previous bone is B-bone too, use average handle direction. */
+ h1[1] -= length;
+ roll1 = 0.0f;
+ }
+
+ normalize_v3(h1);
+ negate_v3(h1);
+
+ if (!param->prev_bbone) {
+ /* Find the previous roll to interpolate. */
+ copy_m3_m4(mat3, param->prev_mat);
+ mat3_vec_to_roll(mat3, h1, &roll1);
+ }
+ }
+ else {
+ h1[0] = 0.0f; h1[1] = 1.0; h1[2] = 0.0f;
+ roll1 = 0.0f;
+ }
+
+ if (param->use_next) {
+ copy_v3_v3(h2, param->next_h);
+
+ /* If next bone is B-bone too, use average handle direction. */
+ if (param->next_bbone) {
+ /* pass */
+ }
+ else {
+ h2[1] -= length;
+ }
+
+ normalize_v3(h2);
+
+ /* Find the next roll to interpolate as well. */
+ copy_m3_m4(mat3, param->next_mat);
+ mat3_vec_to_roll(mat3, h2, &roll2);
}
else {
h2[0] = 0.0f; h2[1] = 1.0f; h2[2] = 0.0f;
@@ -613,10 +712,8 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
{
const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f);
- const float combined_ease1 = bone->ease1 + (!rest ? pchan->ease1 : 0.0f);
- const float combined_ease2 = bone->ease2 + (!rest ? pchan->ease2 : 0.0f);
- const float hlength1 = combined_ease1 * circle_factor;
- const float hlength2 = combined_ease2 * circle_factor;
+ const float hlength1 = param->ease1 * circle_factor;
+ const float hlength2 = param->ease2 * circle_factor;
/* and only now negate h2 */
mul_v3_fl(h1, hlength1);
@@ -638,67 +735,56 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
* end up animating
*/
{
- /* add extra rolls */
- roll1 += bone->roll1 + (!rest ? pchan->roll1 : 0.0f);
- roll2 += bone->roll2 + (!rest ? pchan->roll2 : 0.0f);
-
- if (bone->flag & BONE_ADD_PARENT_END_ROLL) {
- if (prev) {
- if (prev->bone)
- roll1 += prev->bone->roll2;
+ /* Add extra rolls. */
+ roll1 += param->roll1;
+ roll2 += param->roll2;
- if (!rest)
- roll1 += prev->roll2;
- }
- }
-
- /* extra curve x / y */
+ /* Extra curve x / y */
/* NOTE: Scale correction factors here are to compensate for some random floating-point glitches
* when scaling up the bone or it's parent by a factor of approximately 8.15/6, which results
* in the bone length getting scaled up too (from 1 to 8), causing the curve to flatten out.
*/
- const float xscale_correction = (do_scale) ? scale[0] : 1.0f;
- const float yscale_correction = (do_scale) ? scale[2] : 1.0f;
+ const float xscale_correction = (param->do_scale) ? param->scale[0] : 1.0f;
+ const float yscale_correction = (param->do_scale) ? param->scale[2] : 1.0f;
- h1[0] += (bone->curveInX + (!rest ? pchan->curveInX : 0.0f)) * xscale_correction;
- h1[2] += (bone->curveInY + (!rest ? pchan->curveInY : 0.0f)) * yscale_correction;
+ h1[0] += param->curveInX * xscale_correction;
+ h1[2] += param->curveInY * yscale_correction;
- h2[0] += (bone->curveOutX + (!rest ? pchan->curveOutX : 0.0f)) * xscale_correction;
- h2[2] += (bone->curveOutY + (!rest ? pchan->curveOutY : 0.0f)) * yscale_correction;
+ h2[0] += param->curveOutX * xscale_correction;
+ h2[2] += param->curveOutY * yscale_correction;
}
- /* make curve */
- if (bone->segments > MAX_BBONE_SUBDIV)
- bone->segments = MAX_BBONE_SUBDIV;
+ /* Make curve. */
+ CLAMP_MAX(param->segments, MAX_BBONE_SUBDIV);
BKE_curve_forward_diff_bezier(0.0f, h1[0], h2[0], 0.0f, data[0], MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(0.0f, h1[1], length + h2[1], length, data[0] + 1, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(0.0f, h1[2], h2[2], 0.0f, data[0] + 2, MAX_BBONE_SUBDIV, 4 * sizeof(float));
BKE_curve_forward_diff_bezier(roll1, roll1 + 0.390464f * (roll2 - roll1), roll2 - 0.390464f * (roll2 - roll1), roll2, data[0] + 3, MAX_BBONE_SUBDIV, 4 * sizeof(float));
- equalize_bbone_bezier(data[0], bone->segments); /* note: does stride 4! */
+ equalize_bbone_bezier(data[0], param->segments); /* note: does stride 4! */
- /* make transformation matrices for the segments for drawing */
- for (a = 0, fp = data[0]; a < bone->segments; a++, fp += 4) {
+ /* Make transformation matrices for the segments for drawing. */
+ for (a = 0, fp = data[0]; a < param->segments; a++, fp += 4) {
sub_v3_v3v3(h1, fp + 4, fp);
vec_roll_to_mat3(h1, fp[3], mat3); /* fp[3] is roll */
copy_m4_m3(result_array[a].mat, mat3);
copy_v3_v3(result_array[a].mat[3], fp);
- if (do_scale) {
- /* correct for scaling when this matrix is used in scaled space */
+ if (param->do_scale) {
+ /* Correct for scaling when this matrix is used in scaled space. */
mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat);
}
/* BBone scale... */
{
- const int num_segments = bone->segments;
+ const int num_segments = param->segments;
- const float scaleIn = bone->scaleIn * (!rest ? pchan->scaleIn : 1.0f);
+ const float scaleIn = param->scaleIn;
const float scaleFactorIn = 1.0f + (scaleIn - 1.0f) * ((float)(num_segments - a) / (float)num_segments);
- const float scaleOut = bone->scaleOut * (!rest ? pchan->scaleOut : 1.0f);
+ const float scaleOut = param->scaleOut;
const float scaleFactorOut = 1.0f + (scaleOut - 1.0f) * ((float)(a + 1) / (float)num_segments);
const float scalefac = scaleFactorIn * scaleFactorOut;
@@ -714,8 +800,9 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
/*mul_m4_series(result_array[a].mat, ibscalemat, result_array[a].mat, bscalemat);*/
mul_m4_series(result_array[a].mat, result_array[a].mat, bscalemat);
}
-
}
+
+ return param->segments;
}
/* ************ Armature Deform ******************* */
@@ -734,8 +821,8 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info
DualQuat *b_bone_dual_quats = NULL;
int a;
- b_bone_spline_setup(pchan, 0, b_bone);
- b_bone_spline_setup(pchan, 1, b_bone_rest);
+ b_bone_spline_setup(pchan, false, b_bone);
+ b_bone_spline_setup(pchan, true, b_bone_rest);
/* allocate b_bone matrices and dual quats */
b_bone_mats = MEM_mallocN((1 + bone->segments) * sizeof(Mat4), "BBone defmats");
@@ -972,9 +1059,10 @@ static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index)
}
}
-void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
- float (*defMats)[3][3], int numVerts, int deformflag,
- float (*prevCos)[3], const char *defgrp_name)
+void armature_deform_verts(
+ Object *armOb, Object *target, const Mesh *mesh, float (*vertexCos)[3],
+ float (*defMats)[3][3], int numVerts, int deformflag,
+ float (*prevCos)[3], const char *defgrp_name, bGPDstroke *gps)
{
bPoseChanDeform *pdef_info_array;
bPoseChanDeform *pdef_info = NULL;
@@ -1028,7 +1116,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
/* get the def_nr for the overall armature vertex group if present */
armature_def_nr = defgroup_name_index(target, defgrp_name);
- if (ELEM(target->type, OB_MESH, OB_LATTICE)) {
+ if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
defbase_tot = BLI_listbase_count(&target->defbase);
if (target->type == OB_MESH) {
@@ -1037,20 +1125,25 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
if (dverts)
target_totvert = me->totvert;
}
- else {
+ else if (target->type == OB_LATTICE) {
Lattice *lt = target->data;
dverts = lt->dvert;
if (dverts)
target_totvert = lt->pntsu * lt->pntsv * lt->pntsw;
}
+ else if (target->type == OB_GPENCIL) {
+ dverts = gps->dvert;
+ if (dverts)
+ target_totvert = gps->totpoints;
+ }
}
/* get a vertex-deform-index to posechannel array */
if (deformflag & ARM_DEF_VGROUP) {
- if (ELEM(target->type, OB_MESH, OB_LATTICE)) {
- /* if we have a DerivedMesh, only use dverts if it has them */
- if (dm) {
- use_dverts = (dm->getVertDataArray(dm, CD_MDEFORMVERT) != NULL);
+ if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) {
+ /* if we have a Mesh, only use dverts if it has them */
+ if (mesh) {
+ use_dverts = (mesh->dvert != NULL);
}
else if (dverts) {
use_dverts = true;
@@ -1112,8 +1205,10 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
}
if (use_dverts || armature_def_nr != -1) {
- if (dm)
- dvert = dm->getVertData(dm, i, CD_MDEFORMVERT);
+ if (mesh) {
+ BLI_assert(i < mesh->totvert);
+ dvert = mesh->dvert + i;
+ }
else if (dverts && i < target_totvert)
dvert = dverts + i;
else
@@ -1149,7 +1244,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
MDeformWeight *dw = dvert->dw;
int deformed = 0;
unsigned int j;
-
+ float acum_weight = 0;
for (j = dvert->totweight; j != 0; j--, dw++) {
const int index = dw->def_nr;
if (index >= 0 && index < defbase_tot && (pchan = defnrToPC[index])) {
@@ -1163,7 +1258,21 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail,
bone->rad_head, bone->rad_tail, bone->dist);
}
+
+ /* check limit of weight */
+ if (target->type == OB_GPENCIL) {
+ if (acum_weight + weight >= 1.0f) {
+ weight = 1.0f - acum_weight;
+ }
+ acum_weight += weight;
+ }
+
pchan_bone_deform(pchan, pdef_info, weight, vec, dq, smat, co, &contrib);
+
+ /* if acumulated weight limit exceed, exit loop */
+ if ((target->type == OB_GPENCIL) && (acum_weight >= 1.0f)) {
+ break;
+ }
}
}
/* if there are vertexgroups but not groups with bones
@@ -1202,7 +1311,9 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
smat = summat;
}
else {
- mul_v3_fl(vec, armature_weight / contrib);
+ if (target->type != OB_GPENCIL) {
+ mul_v3_fl(vec, armature_weight / contrib);
+ }
add_v3_v3v3(co, vec, co);
}
@@ -1463,16 +1574,16 @@ void BKE_armature_loc_pose_to_bone(bPoseChannel *pchan, const float inloc[3], fl
copy_v3_v3(outloc, nLocMat[3]);
}
-void BKE_armature_mat_pose_to_bone_ex(Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
+void BKE_armature_mat_pose_to_bone_ex(struct Depsgraph *depsgraph, Object *ob, bPoseChannel *pchan, float inmat[4][4], float outmat[4][4])
{
bPoseChannel work_pchan = *pchan;
/* recalculate pose matrix with only parent transformations,
* bone loc/sca/rot is ignored, scene and frame are not used. */
- BKE_pose_where_is_bone(NULL, ob, &work_pchan, 0.0f, false);
+ BKE_pose_where_is_bone(depsgraph, NULL, ob, &work_pchan, 0.0f, false);
/* find the matrix, need to remove the bone transforms first so this is
- * calculated as a matrix to set rather then a difference ontop of whats
+ * calculated as a matrix to set rather then a difference ontop of what's
* already there. */
unit_m4(outmat);
BKE_pchan_apply_mat4(&work_pchan, outmat, false);
@@ -1594,21 +1705,28 @@ void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float
/* Computes vector and roll based on a rotation.
* "mat" must contain only a rotation, and no scaling. */
-void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll)
+void mat3_to_vec_roll(const float mat[3][3], float r_vec[3], float *r_roll)
{
if (r_vec) {
copy_v3_v3(r_vec, mat[1]);
}
if (r_roll) {
- float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
+ mat3_vec_to_roll(mat, mat[1], r_roll);
+ }
+}
- vec_roll_to_mat3(mat[1], 0.0f, vecmat);
- invert_m3_m3(vecmatinv, vecmat);
- mul_m3_m3m3(rollmat, vecmatinv, mat);
+/* Computes roll around the vector that best approximates the matrix.
+ * If vec is the Y vector from purely rotational mat, result should be exact. */
+void mat3_vec_to_roll(const float mat[3][3], const float vec[3], float *r_roll)
+{
+ float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
- *r_roll = atan2f(rollmat[2][0], rollmat[2][2]);
- }
+ vec_roll_to_mat3(vec, 0.0f, vecmat);
+ invert_m3_m3(vecmatinv, vecmat);
+ mul_m3_m3m3(rollmat, vecmatinv, mat);
+
+ *r_roll = atan2f(rollmat[2][0], rollmat[2][2]);
}
/* Calculates the rest matrix of a bone based on its vector and a roll around that vector. */
@@ -1835,6 +1953,8 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected
pchanw.parent = pchan->parent;
pchanw.child = pchan->child;
pchanw.custom_tx = pchan->custom_tx;
+ pchanw.bbone_prev = pchan->bbone_prev;
+ pchanw.bbone_next = pchan->bbone_next;
pchanw.mpath = pchan->mpath;
pchan->mpath = NULL;
@@ -1950,9 +2070,36 @@ void BKE_pose_clear_pointers(bPose *pose)
}
}
-/* only after leave editmode, duplicating, validating older files, library syncing */
-/* NOTE: pose->flag is set for it */
-void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones)
+void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose)
+{
+ GHash *bone_hash = BKE_armature_bone_from_name_map(armature);
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone = BLI_ghash_lookup(bone_hash, pchan->name);
+ }
+ BLI_ghash_free(bone_hash, NULL, NULL);
+}
+
+/** Find the matching pose channel using the bone name, if not NULL. */
+static bPoseChannel *pose_channel_find_bone(bPose *pose, Bone *bone)
+{
+ return (bone != NULL) ? BKE_pose_channel_find_name(pose, bone->name) : NULL;
+}
+
+/** Update the links for the B-Bone handles from Bone data. */
+void BKE_pchan_rebuild_bbone_handles(bPose *pose, bPoseChannel *pchan)
+{
+ pchan->bbone_prev = pose_channel_find_bone(pose, pchan->bone->bbone_prev);
+ pchan->bbone_next = pose_channel_find_bone(pose, pchan->bone->bbone_next);
+}
+
+/**
+ * Only after leave editmode, duplicating, validating older files, library syncing.
+ *
+ * \note pose->flag is set for it.
+ *
+ * \param bmain May be NULL, only used to tag depsgraph as being dirty...
+ */
+void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user)
{
Bone *bone;
bPose *pose;
@@ -1981,40 +2128,39 @@ void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones)
for (pchan = pose->chanbase.first; pchan; pchan = next) {
next = pchan->next;
if (pchan->bone == NULL) {
- BKE_pose_channel_free(pchan);
+ BKE_pose_channel_free_ex(pchan, do_id_user);
BKE_pose_channels_hash_free(pose);
BLI_freelinkN(&pose->chanbase, pchan);
}
}
+
+ BKE_pose_channels_hash_make(pose);
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* Find the custom B-Bone handles. */
+ BKE_pchan_rebuild_bbone_handles(pose, pchan);
+ }
+
/* printf("rebuild pose %s, %d bones\n", ob->id.name, counter); */
/* synchronize protected layers with proxy */
- if (ob->proxy) {
+ /* HACK! To preserve 2.7x behavior that you always can pose even locked bones,
+ * do not do any restoration if this is a COW temp copy! */
+ /* Switched back to just NO_MAIN tag, for some reasons (c) using COW tag was working this morning, but not anymore... */
+ if (ob->proxy != NULL && (ob->id.tag & LIB_TAG_NO_MAIN) == 0) {
BKE_object_copy_proxy_drivers(ob, ob->proxy);
pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected);
}
- BKE_pose_update_constraint_flags(ob->pose); /* for IK detection for example */
-
-#ifdef WITH_LEGACY_DEPSGRAPH
- /* the sorting */
- /* Sorting for new dependnecy graph is done on the scene graph level. */
- if (counter > 1 && sort_bones) {
- DAG_pose_sort(ob);
- }
-#else
- UNUSED_VARS(sort_bones);
-#endif
+ BKE_pose_update_constraint_flags(pose); /* for IK detection for example */
- ob->pose->flag &= ~POSE_RECALC;
- ob->pose->flag |= POSE_WAS_REBUILT;
+ pose->flag &= ~POSE_RECALC;
+ pose->flag |= POSE_WAS_REBUILT;
- BKE_pose_channels_hash_make(ob->pose);
-}
-
-void BKE_pose_rebuild(Object *ob, bArmature *arm)
-{
- BKE_pose_rebuild_ex(ob, arm, true);
+ /* Rebuilding poses forces us to also rebuild the dependency graph, since there is one node per pose/bone... */
+ if (bmain != NULL) {
+ DEG_relations_tag_update(bmain);
+ }
}
/* ********************** THE POSE SOLVER ******************* */
@@ -2071,132 +2217,6 @@ void BKE_pchan_calc_mat(bPoseChannel *pchan)
BKE_pchan_to_mat4(pchan, pchan->chan_mat);
}
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
-
-/* NLA strip modifiers */
-static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseChannel *pchan)
-{
- bActionModifier *amod;
- bActionStrip *strip, *strip2;
- float scene_cfra = BKE_scene_frame_get(scene);
- int do_modif;
-
- for (strip = armob->nlastrips.first; strip; strip = strip->next) {
- do_modif = false;
-
- if (scene_cfra >= strip->start && scene_cfra <= strip->end)
- do_modif = true;
-
- if ((scene_cfra > strip->end) && (strip->flag & ACTSTRIP_HOLDLASTFRAME)) {
- do_modif = true;
-
- /* if there are any other strips active, ignore modifiers for this strip -
- * 'hold' option should only hold action modifiers if there are
- * no other active strips */
- for (strip2 = strip->next; strip2; strip2 = strip2->next) {
- if (strip2 == strip) continue;
-
- if (scene_cfra >= strip2->start && scene_cfra <= strip2->end) {
- if (!(strip2->flag & ACTSTRIP_MUTE))
- do_modif = false;
- }
- }
-
- /* if there are any later, activated, strips with 'hold' set, they take precedence,
- * so ignore modifiers for this strip */
- for (strip2 = strip->next; strip2; strip2 = strip2->next) {
- if (scene_cfra < strip2->start) continue;
- if ((strip2->flag & ACTSTRIP_HOLDLASTFRAME) && !(strip2->flag & ACTSTRIP_MUTE)) {
- do_modif = false;
- }
- }
- }
-
- if (do_modif) {
- /* temporal solution to prevent 2 strips accumulating */
- if (scene_cfra == strip->end && strip->next && strip->next->start == scene_cfra)
- continue;
-
- for (amod = strip->modifiers.first; amod; amod = amod->next) {
- switch (amod->type) {
- case ACTSTRIP_MOD_DEFORM:
- {
- /* validate first */
- if (amod->ob && amod->ob->type == OB_CURVE && amod->channel[0]) {
-
- if (STREQ(pchan->name, amod->channel)) {
- float mat4[4][4], mat3[3][3];
-
- curve_deform_vector(scene, amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
- copy_m4_m4(mat4, pchan->pose_mat);
- mul_m4_m3m4(pchan->pose_mat, mat3, mat4);
-
- }
- }
- }
- break;
- case ACTSTRIP_MOD_NOISE:
- {
- if (STREQ(pchan->name, amod->channel)) {
- float nor[3], loc[3], ofs;
- float eul[3], size[3], eulo[3], sizeo[3];
-
- /* calculate turbulance */
- ofs = amod->turbul / 200.0f;
-
- /* make a copy of starting conditions */
- copy_v3_v3(loc, pchan->pose_mat[3]);
- mat4_to_eul(eul, pchan->pose_mat);
- mat4_to_size(size, pchan->pose_mat);
- copy_v3_v3(eulo, eul);
- copy_v3_v3(sizeo, size);
-
- /* apply noise to each set of channels */
- if (amod->channels & 4) {
- /* for scaling */
- nor[0] = BLI_gNoise(amod->noisesize, size[0] + ofs, size[1], size[2], 0, 0) - ofs;
- nor[1] = BLI_gNoise(amod->noisesize, size[0], size[1] + ofs, size[2], 0, 0) - ofs;
- nor[2] = BLI_gNoise(amod->noisesize, size[0], size[1], size[2] + ofs, 0, 0) - ofs;
- add_v3_v3(size, nor);
-
- if (sizeo[0] != 0)
- mul_v3_fl(pchan->pose_mat[0], size[0] / sizeo[0]);
- if (sizeo[1] != 0)
- mul_v3_fl(pchan->pose_mat[1], size[1] / sizeo[1]);
- if (sizeo[2] != 0)
- mul_v3_fl(pchan->pose_mat[2], size[2] / sizeo[2]);
- }
- if (amod->channels & 2) {
- /* for rotation */
- nor[0] = BLI_gNoise(amod->noisesize, eul[0] + ofs, eul[1], eul[2], 0, 0) - ofs;
- nor[1] = BLI_gNoise(amod->noisesize, eul[0], eul[1] + ofs, eul[2], 0, 0) - ofs;
- nor[2] = BLI_gNoise(amod->noisesize, eul[0], eul[1], eul[2] + ofs, 0, 0) - ofs;
-
- compatible_eul(nor, eulo);
- add_v3_v3(eul, nor);
- compatible_eul(eul, eulo);
-
- loc_eul_size_to_mat4(pchan->pose_mat, loc, eul, size);
- }
- if (amod->channels & 1) {
- /* for location */
- nor[0] = BLI_gNoise(amod->noisesize, loc[0] + ofs, loc[1], loc[2], 0, 0) - ofs;
- nor[1] = BLI_gNoise(amod->noisesize, loc[0], loc[1] + ofs, loc[2], 0, 0) - ofs;
- nor[2] = BLI_gNoise(amod->noisesize, loc[0], loc[1], loc[2] + ofs, 0, 0) - ofs;
-
- add_v3_v3v3(pchan->pose_mat[3], loc, nor);
- }
- }
- }
- break;
- }
- }
- }
- }
-}
-
-#endif
-
/* calculate tail of posechannel */
void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
{
@@ -2211,7 +2231,9 @@ void BKE_pose_where_is_bone_tail(bPoseChannel *pchan)
/* pchan is validated, as having bone and parent pointer
* 'do_extra': when zero skips loc/size/rot, constraints and strip modifiers.
*/
-void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float ctime, bool do_extra)
+void BKE_pose_where_is_bone(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, bPoseChannel *pchan, float ctime, bool do_extra)
{
/* This gives a chan_mat with actions (ipos) results. */
if (do_extra)
@@ -2231,11 +2253,6 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float
}
if (do_extra) {
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
- /* do NLA strip modifiers - i.e. curve follow */
- do_strip_modifiers(scene, ob, bone, pchan);
-#endif
-
/* Do constraints */
if (pchan->constraints.first) {
bConstraintOb *cob;
@@ -2247,10 +2264,10 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float
/* prepare PoseChannel for Constraint solving
* - makes a copy of matrix, and creates temporary struct to use
*/
- cob = BKE_constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, pchan, CONSTRAINT_OBTYPE_BONE);
/* Solve PoseChannel's Constraints */
- BKE_constraints_solve(&pchan->constraints, cob, ctime); /* ctime doesnt alter objects */
+ BKE_constraints_solve(depsgraph, &pchan->constraints, cob, ctime); /* ctime doesn't alter objects */
/* cleanup after Constraint Solving
* - applies matrix back to pchan, and frees temporary struct used
@@ -2272,7 +2289,7 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float
/* This only reads anim data from channels, and writes to channels */
/* This is the only function adding poses */
-void BKE_pose_where_is(Scene *scene, Object *ob)
+void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
bArmature *arm;
Bone *bone;
@@ -2286,8 +2303,10 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
if (ELEM(NULL, arm, scene))
return;
- if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC))
- BKE_pose_rebuild(ob, arm);
+ if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) {
+ /* WARNING! passing NULL bmain here means we won't tag depsgraph's as dirty - hopefully this is OK. */
+ BKE_pose_rebuild(NULL, ob, arm, true);
+ }
ctime = BKE_scene_frame_get(scene); /* not accurate... */
@@ -2311,7 +2330,7 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
}
/* 2a. construct the IK tree (standard IK) */
- BIK_initialize_tree(scene, ob, ctime);
+ BIK_initialize_tree(depsgraph, scene, ob, ctime);
/* 2b. construct the Spline IK trees
* - this is not integrated as an IK plugin, since it should be able
@@ -2323,15 +2342,15 @@ void BKE_pose_where_is(Scene *scene, Object *ob)
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* 4a. if we find an IK root, we handle it separated */
if (pchan->flag & POSE_IKTREE) {
- BIK_execute_tree(scene, ob, pchan, ctime);
+ BIK_execute_tree(depsgraph, scene, ob, pchan, ctime);
}
/* 4b. if we find a Spline IK root, we handle it separated too */
else if (pchan->flag & POSE_IKSPLINE) {
- BKE_splineik_execute_tree(scene, ob, pchan, ctime);
+ BKE_splineik_execute_tree(depsgraph, scene, ob, pchan, ctime);
}
/* 5. otherwise just call the normal solver */
else if (!(pchan->flag & POSE_DONE)) {
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
}
/* 6. release the IK tree */
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index cb4237f51b4..2d9e2a0d84b 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -26,6 +26,10 @@
* Defines and code for core node types
*/
+/** \file blender/blenkernel/intern/armature_update.c
+ * \ingroup bke
+ */
+
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
@@ -41,7 +45,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"
@@ -113,9 +116,11 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
* currently for paths to work it needs to go through the bevlist/displist system (ton)
*/
+ /* TODO: Make sure this doesn't crash. */
+#if 0
/* only happens on reload file, but violates depsgraph still... fix! */
if (ELEM(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
- BKE_displist_make_curveTypes(scene, ikData->tar, 0);
+ BKE_displist_make_curveTypes(depsgraph, scene, ikData->tar, 0);
/* path building may fail in EditMode after removing verts [#33268]*/
if (ELEM(NULL, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
@@ -123,6 +128,9 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
return;
}
}
+#else
+ (void) scene;
+#endif
}
/* find the root bone and the chain of bones from the root to the tip
@@ -197,7 +205,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
/* get the current length of the curve */
/* NOTE: this is assumed to be correct even after the curve was resized */
- splineLen = ikData->tar->curve_cache->path->totdist;
+ splineLen = ikData->tar->runtime.curve_cache->path->totdist;
/* calculate the scale factor to multiply all the path values by so that the
* bone chain retains its current length, such that
@@ -261,15 +269,16 @@ static void splineik_init_tree(Scene *scene, Object *ob, float UNUSED(ctime))
/* ----------- */
/* Evaluate spline IK for a given bone */
-static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
- int index, float ctime)
+static void splineik_evaluate_bone(
+ struct Depsgraph *depsgraph, tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan,
+ int index, float ctime)
{
bSplineIKConstraint *ikData = tree->ikData;
float poseHead[3], poseTail[3], poseMat[4][4];
float splineVec[3], scaleFac, radius = 1.0f;
/* firstly, calculate the bone matrix the standard way, since this is needed for roll control */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
copy_v3_v3(poseHead, pchan->pose_head);
copy_v3_v3(poseTail, pchan->pose_tail);
@@ -511,7 +520,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
}
/* Evaluate the chain starting from the nominated bone */
-static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+static void splineik_execute_tree(struct Depsgraph *depsgraph, Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
{
tSplineIK_Tree *tree;
@@ -525,7 +534,7 @@ static void splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_
*/
for (i = tree->chainlen - 1; i >= 0; i--) {
bPoseChannel *pchan = tree->chain[i];
- splineik_evaluate_bone(tree, scene, ob, pchan, i, ctime);
+ splineik_evaluate_bone(depsgraph, tree, scene, ob, pchan, i, ctime);
}
/* free the tree info specific to SplineIK trees now */
@@ -544,30 +553,44 @@ void BKE_pose_splineik_init_tree(Scene *scene, Object *ob, float ctime)
splineik_init_tree(scene, ob, ctime);
}
-void BKE_splineik_execute_tree(Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime)
+void BKE_splineik_execute_tree(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, bPoseChannel *pchan_root, float ctime)
{
- splineik_execute_tree(scene, ob, pchan_root, ctime);
+ splineik_execute_tree(depsgraph, scene, ob, pchan_root, ctime);
}
/* *************** Depsgraph evaluation callbacks ************ */
+static void pose_pchan_index_create(bPose *pose)
+{
+ const int num_channels = BLI_listbase_count(&pose->chanbase);
+ pose->chan_array = MEM_malloc_arrayN(
+ num_channels, sizeof(bPoseChannel *), "pose->chan_array");
+ int pchan_index = 0;
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ pose->chan_array[pchan_index++] = pchan;
+ }
+}
+
BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index)
{
bPose *pose = ob->pose;
BLI_assert(pose != NULL);
+ BLI_assert(pose->chan_array != NULL);
BLI_assert(pchan_index >= 0);
BLI_assert(pchan_index < MEM_allocN_len(pose->chan_array) / sizeof(bPoseChannel *));
return pose->chan_array[pchan_index];
}
-void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_init(struct Depsgraph *depsgraph,
Scene *UNUSED(scene),
Object *ob)
{
bPose *pose = ob->pose;
BLI_assert(pose != NULL);
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
@@ -578,23 +601,19 @@ void BKE_pose_eval_init(EvaluationContext *UNUSED(eval_ctx),
/* imat is needed for solvers. */
invert_m4_m4(ob->imat, ob->obmat);
- const int num_channels = BLI_listbase_count(&pose->chanbase);
- pose->chan_array = MEM_malloc_arrayN(
- num_channels, sizeof(bPoseChannel *), "pose->chan_array");
-
/* clear flags */
- int pchan_index = 0;
for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE);
- pose->chan_array[pchan_index++] = pchan;
}
+
+ pose_pchan_index_create(pose);
}
-void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
@@ -602,7 +621,7 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
return;
}
/* construct the IK tree (standard IK) */
- BIK_initialize_tree(scene, ob, ctime);
+ BIK_initialize_tree(depsgraph, scene, ob, ctime);
/* construct the Spline IK trees
* - this is not integrated as an IK plugin, since it should be able
* to function in conjunction with standard IK
@@ -610,14 +629,14 @@ void BKE_pose_eval_init_ik(EvaluationContext *UNUSED(eval_ctx),
BKE_pose_splineik_init_tree(scene, ob, ctime);
}
-void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_eval_bone(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int pchan_index)
{
bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
+ depsgraph, __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
BLI_assert(ob->type == OB_ARMATURE);
bArmature *arm = (bArmature *)ob->data;
if (arm->edbo || (arm->flag & ARM_RESTPOS)) {
@@ -640,21 +659,21 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
if ((pchan->flag & POSE_DONE) == 0) {
/* TODO(sergey): Use time source node for time. */
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
}
}
}
}
-void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_constraints_evaluate(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int pchan_index)
{
bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
+ depsgraph, __func__, ob->id.name, ob, "pchan", pchan->name, pchan);
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
@@ -665,42 +684,51 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
else {
if ((pchan->flag & POSE_DONE) == 0) {
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
+ BKE_pose_where_is_bone(depsgraph, scene, ob, pchan, ctime, 1);
}
}
}
-void BKE_pose_bone_done(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_bone_done(struct Depsgraph *depsgraph,
struct Object *ob,
int pchan_index)
{
bPoseChannel *pchan = pose_pchan_get_indexed(ob, pchan_index);
float imat[4][4];
- DEG_debug_print_eval(__func__, pchan->name, pchan);
+ DEG_debug_print_eval(depsgraph, __func__, pchan->name, pchan);
if (pchan->bone) {
invert_m4_m4(imat, pchan->bone->arm_mat);
mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat);
}
+ bArmature *arm = (bArmature *)ob->data;
+ if (DEG_is_active(depsgraph) && arm->edbo == NULL) {
+ bPoseChannel *pchan_orig = pchan->orig_pchan;
+ copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat);
+ copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat);
+ copy_v3_v3(pchan_orig->pose_head, pchan->pose_mat[3]);
+ copy_m4_m4(pchan_orig->constinv, pchan->constinv);
+ BKE_pose_where_is_bone_tail(pchan_orig);
+ }
}
-void BKE_pose_iktree_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_iktree_evaluate(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int rootchan_index)
{
bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
+ depsgraph, __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
}
- BIK_execute_tree(scene, ob, rootchan, ctime);
+ BIK_execute_tree(depsgraph, scene, ob, rootchan, ctime);
}
-void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
+void BKE_pose_splineik_evaluate(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
int rootchan_index)
@@ -708,47 +736,73 @@ void BKE_pose_splineik_evaluate(EvaluationContext *UNUSED(eval_ctx),
{
bPoseChannel *rootchan = pose_pchan_get_indexed(ob, rootchan_index);
DEG_debug_print_eval_subdata(
- __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
+ depsgraph, __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan);
BLI_assert(ob->type == OB_ARMATURE);
const float ctime = BKE_scene_frame_get(scene); /* not accurate... */
bArmature *arm = (bArmature *)ob->data;
if (arm->flag & ARM_RESTPOS) {
return;
}
- BKE_splineik_execute_tree(scene, ob, rootchan, ctime);
+ BKE_splineik_execute_tree(depsgraph, scene, ob, rootchan, ctime);
}
-void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
- Scene *scene,
- Object *ob)
+void BKE_pose_eval_cleanup(struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
{
bPose *pose = ob->pose;
BLI_assert(pose != NULL);
float ctime = BKE_scene_frame_get(scene); /* not accurate... */
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type == OB_ARMATURE);
/* release the IK tree */
BIK_release_tree(scene, ob, ctime);
- ob->recalc &= ~OB_RECALC_ALL;
+ BLI_assert(pose->chan_array != NULL);
+ MEM_freeN(pose->chan_array);
+ pose->chan_array = NULL;
+}
+
+void BKE_pose_eval_proxy_init(struct Depsgraph *depsgraph, Object *object)
+{
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+
+ pose_pchan_index_create(object->pose);
+}
+
+void BKE_pose_eval_proxy_cleanup(struct Depsgraph *depsgraph, Object *object)
+{
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ bPose *pose = object->pose;
BLI_assert(pose->chan_array != NULL);
MEM_freeN(pose->chan_array);
pose->chan_array = NULL;
}
-void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+void BKE_pose_eval_proxy_copy_bone(
+ struct Depsgraph *depsgraph,
+ Object *object,
+ int pchan_index)
{
- BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL);
- DEG_debug_print_eval(__func__, ob->id.name, ob);
- if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
- printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
- ob->id.name + 2, ob->proxy_from->id.name + 2);
- }
- /* Rest of operations are NO-OP in depsgraph, so can clear
- * flag now.
+ BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index);
+ /* TODO(sergey): Use indexec lookup, once it's guaranteed to be kept
+ * around for the time while proxies are evaluating.
*/
- ob->recalc &= ~OB_RECALC_ALL;
+#if 0
+ bPoseChannel *pchan_from = pose_pchan_get_indexed(
+ object->proxy_from, pchan_index);
+#else
+ bPoseChannel *pchan_from = BKE_pose_channel_find_name(
+ object->proxy_from->pose, pchan->name);
+#endif
+ BLI_assert(pchan != NULL);
+ BLI_assert(pchan_from != NULL);
+ BKE_pose_copyesult_pchan_result(pchan, pchan_from);
}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index ba20dbaddb0..d0dea75860e 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -48,20 +48,25 @@
#include "BKE_addon.h"
#include "BKE_blender.h" /* own include */
#include "BKE_blender_version.h" /* own include */
+#include "BKE_blender_user_menu.h"
#include "BKE_blendfile.h"
#include "BKE_brush.h"
#include "BKE_cachefile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sequencer.h"
+#include "BKE_studiolight.h"
+
+#include "DEG_depsgraph.h"
#include "RE_pipeline.h"
#include "RE_render_ext.h"
@@ -80,6 +85,8 @@ char versionstr[48] = "";
void BKE_blender_free(void)
{
/* samples are in a global list..., also sets G_MAIN->sound->sample NULL */
+
+ BKE_studiolight_free(); /* needs to run before main free as wm is still referenced for icons preview jobs */
BKE_main_free(G_MAIN);
G_MAIN = NULL;
@@ -92,7 +99,7 @@ void BKE_blender_free(void)
IMB_exit();
BKE_cachefiles_exit();
BKE_images_exit();
- DAG_exit();
+ DEG_free_node_types();
BKE_brush_system_exit();
RE_texture_rng_exit();
@@ -201,6 +208,15 @@ static void userdef_free_keymaps(UserDef *userdef)
BLI_listbase_clear(&userdef->user_keymaps);
}
+static void userdef_free_user_menus(UserDef *userdef)
+{
+ for (bUserMenu *um = userdef->user_menus.first, *um_next; um; um = um_next) {
+ um_next = um->next;
+ BKE_blender_user_menu_item_free_list(&um->items);
+ MEM_freeN(um);
+ }
+}
+
static void userdef_free_addons(UserDef *userdef)
{
for (bAddon *addon = userdef->addons.first, *addon_next; addon; addon = addon_next) {
@@ -221,6 +237,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
#endif
userdef_free_keymaps(userdef);
+ userdef_free_user_menus(userdef);
userdef_free_addons(userdef);
if (clear_fonts) {
@@ -236,6 +253,7 @@ void BKE_blender_userdef_data_free(UserDef *userdef, bool clear_fonts)
BLI_freelistN(&userdef->uifonts);
BLI_freelistN(&userdef->themes);
+
#undef U
}
@@ -283,11 +301,13 @@ void BKE_blender_userdef_app_template_data_swap(UserDef *userdef_a, UserDef *use
DATA_SWAP(font_path_ui_mono);
DATA_SWAP(keyconfigstr);
+ DATA_SWAP(gizmo_flag);
DATA_SWAP(app_flag);
/* We could add others. */
FLAG_SWAP(uiflag, int, USER_QUIT_PROMPT);
+#undef SWAP_TYPELESS
#undef DATA_SWAP
#undef LIST_SWAP
#undef FLAG_SWAP
diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c
index e57524af546..7b149761952 100644
--- a/source/blender/blenkernel/intern/blender_copybuffer.c
+++ b/source/blender/blenkernel/intern/blender_copybuffer.c
@@ -44,12 +44,15 @@
#include "BKE_blender_copybuffer.h" /* own include */
#include "BKE_blendfile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -95,7 +98,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor
/* Here appending/linking starts. */
Main *mainl = BLO_library_link_begin(bmain_dst, &bh, libname);
BLO_library_link_copypaste(mainl, bh);
- BLO_library_link_end(mainl, &bh, 0, NULL, NULL);
+ BLO_library_link_end(mainl, &bh, 0, NULL, NULL, NULL);
/* Mark all library linked objects to be updated. */
BKE_main_lib_objects_recalc_all(bmain_dst);
IMB_colormanagement_check_file_config(bmain_dst);
@@ -117,7 +120,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Main *mainl = NULL;
Library *lib;
BlendHandle *bh;
@@ -129,7 +132,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
return false;
}
- BKE_scene_base_deselect_all(scene);
+ BKE_view_layer_base_deselect_all(view_layer);
/* tag everything, all untagged data can be made local
* its also generally useful to know what is new
@@ -142,7 +145,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
BLO_library_link_copypaste(mainl, bh);
- BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+ BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer);
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
@@ -157,7 +160,11 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
/* recreate dependency graph to include new objects */
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
+
+ /* Tag update the scene to flush base collection settings, since the new object is added to a
+ * new (active) collection, not its original collection, thus need recalculation. */
+ DEG_id_tag_update(&scene->id, 0);
BLO_blendhandle_close(bh);
/* remove library... */
diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c
index df2caba0208..a00ad5ff05f 100644
--- a/source/blender/blenkernel/intern/blender_undo.c
+++ b/source/blender/blenkernel/intern/blender_undo.c
@@ -46,17 +46,19 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_appdir.h"
#include "BKE_blender_undo.h" /* own include */
#include "BKE_blendfile.h"
-#include "BKE_appdir.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BLO_undofile.h"
#include "BLO_writefile.h"
+#include "DEG_depsgraph.h"
+
/* -------------------------------------------------------------------- */
/** \name Global Undo
@@ -88,8 +90,8 @@ bool BKE_memfile_undo_decode(MemFileUndoData *mfu, bContext *C)
G.fileflags = fileflags;
if (success) {
- /* important not to update time here, else non keyed tranforms are lost */
- DAG_on_visible_update(bmain, false);
+ /* important not to update time here, else non keyed transforms are lost */
+ DEG_on_visible_update(bmain, false);
}
return success;
diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c
new file mode 100644
index 00000000000..2c18de70e6d
--- /dev/null
+++ b/source/blender/blenkernel/intern/blender_user_menu.c
@@ -0,0 +1,121 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/blender_user_menu.c
+ * \ingroup bke
+ *
+ * User defined menu API.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "DNA_userdef_types.h"
+
+#include "BKE_blender_user_menu.h"
+#include "BKE_idprop.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Type
+ * \{ */
+
+bUserMenu *BKE_blender_user_menu_find(
+ ListBase *lb, char space_type, const char *context)
+{
+ for (bUserMenu *um = lb->first; um; um = um->next) {
+ if ((space_type == um->space_type) &&
+ (STREQ(context, um->context)))
+ {
+ return um;
+ }
+ }
+ return NULL;
+}
+
+bUserMenu *BKE_blender_user_menu_ensure(
+ ListBase *lb, char space_type, const char *context)
+{
+ bUserMenu *um = BKE_blender_user_menu_find(lb, space_type, context);
+ if (um == NULL) {
+ um = MEM_callocN(sizeof(bUserMenu), __func__);
+ um->space_type = space_type;
+ STRNCPY(um->context, context);
+ BLI_addhead(lb, um);
+ }
+ return um;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Item
+ * \{ */
+
+bUserMenuItem *BKE_blender_user_menu_item_add(ListBase *lb, int type)
+{
+ uint size;
+
+ if (type == USER_MENU_TYPE_SEP) {
+ size = sizeof(bUserMenuItem);
+ }
+ else if (type == USER_MENU_TYPE_OPERATOR) {
+ size = sizeof(bUserMenuItem_Op);
+ }
+ else if (type == USER_MENU_TYPE_MENU) {
+ size = sizeof(bUserMenuItem_Menu);
+ }
+ else if (type == USER_MENU_TYPE_PROP) {
+ size = sizeof(bUserMenuItem_Prop);
+ }
+ else {
+ size = sizeof(bUserMenuItem);
+ BLI_assert(0);
+ }
+
+ bUserMenuItem *umi = MEM_callocN(size, __func__);
+ umi->type = type;
+ BLI_addtail(lb, umi);
+ return umi;
+}
+
+void BKE_blender_user_menu_item_free(bUserMenuItem *umi)
+{
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
+ if (umi_op->prop) {
+ IDP_FreeProperty(umi_op->prop);
+ MEM_freeN(umi_op->prop);
+ }
+ }
+ MEM_freeN(umi);
+}
+
+void BKE_blender_user_menu_item_free_list(ListBase *lb)
+{
+ for (bUserMenuItem *umi = lb->first, *umi_next; umi; umi = umi_next) {
+ umi_next = umi->next;
+ BKE_blender_user_menu_item_free(umi);
+ }
+ BLI_listbase_clear(lb);
+}
diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c
index c92648da67c..5f716d191e4 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;
}
}
@@ -164,17 +167,22 @@ static void setup_app_data(
* (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
* see: T43424
*/
+ wmWindow *win;
bScreen *curscreen = NULL;
+ ViewLayer *cur_view_layer;
bool track_undo_scene;
/* comes from readfile.c */
SWAP(ListBase, bmain->wm, bfd->main->wm);
+ SWAP(ListBase, bmain->workspaces, bfd->main->workspaces);
SWAP(ListBase, bmain->screen, bfd->main->screen);
- /* we re-use current screen */
+ /* we re-use current window and screen */
+ win = CTX_wm_window(C);
curscreen = CTX_wm_screen(C);
- /* but use new Scene pointer */
+ /* but use Scene pointer from new file */
curscene = bfd->curscene;
+ cur_view_layer = bfd->cur_view_layer;
track_undo_scene = (mode == LOAD_UNDO && curscreen && curscene && bfd->main->wm.first);
@@ -185,34 +193,41 @@ static void setup_app_data(
if (curscene == NULL) {
curscene = BKE_scene_add(bfd->main, "Empty");
}
+ if (cur_view_layer == NULL) {
+ /* fallback to scene layer */
+ cur_view_layer = BKE_view_layer_default_view(curscene);
+ }
if (track_undo_scene) {
/* keep the old (free'd) scene, let 'blo_lib_link_screen_restore'
* replace it with 'curscene' if its needed */
}
- else {
- /* and we enforce curscene to be in current screen */
- if (curscreen) {
- /* can run in bgmode */
- curscreen->scene = curscene;
- }
+ /* and we enforce curscene to be in current screen */
+ else if (win) { /* can run in bgmode */
+ win->scene = curscene;
}
/* BKE_blender_globals_clear will free G_MAIN, here we can still restore pointers */
- blo_lib_link_screen_restore(bfd->main, curscreen, curscene);
- /* curscreen might not be set when loading without ui (see T44217) so only re-assign if available */
- if (curscreen) {
- curscene = curscreen->scene;
+ blo_lib_link_restore(bfd->main, CTX_wm_manager(C), curscene, cur_view_layer);
+ if (win) {
+ curscene = win->scene;
}
if (track_undo_scene) {
wmWindowManager *wm = bfd->main->wm.first;
if (wm_scene_is_visible(wm, bfd->curscene) == false) {
curscene = bfd->curscene;
- curscreen->scene = curscene;
- BKE_screen_view3d_scene_sync(curscreen);
+ win->scene = curscene;
+ BKE_screen_view3d_scene_sync(curscreen, curscene);
}
}
+
+ /* We need to tag this here because events may be handled immediately after.
+ * only the current screen is important because we wont have to handle
+ * events from multiple screens at once.*/
+ if (curscreen) {
+ BKE_screen_gizmo_tag_refresh(curscreen);
+ }
}
/* free G_MAIN Main database */
@@ -227,6 +242,7 @@ static void setup_app_data(
CTX_data_main_set(C, bmain);
if (bfd->user) {
+
/* only here free userdef themes... */
BKE_blender_userdef_data_set_and_free(bfd->user);
bfd->user = NULL;
@@ -262,12 +278,14 @@ static void setup_app_data(
/* this can happen when active scene was lib-linked, and doesn't exist anymore */
if (CTX_data_scene(C) == NULL) {
+ wmWindow *win = CTX_wm_window(C);
+
/* in case we don't even have a local scene, add one */
if (!bmain->scene.first)
BKE_scene_add(bmain, "Empty");
CTX_data_scene_set(C, bmain->scene.first);
- CTX_wm_screen(C)->scene = CTX_data_scene(C);
+ win->scene = CTX_data_scene(C);
curscene = CTX_data_scene(C);
}
@@ -316,20 +334,27 @@ static void setup_app_data(
wmWindowManager *wm = bmain->wm.first;
if (wm) {
- wmWindow *win;
-
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen && win->screen->scene) /* zealous check... */
- if (win->screen->scene != curscene)
- BKE_scene_set_background(bmain, win->screen->scene);
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene && win->scene != curscene) {
+ BKE_scene_set_background(bmain, win->scene);
+ }
}
}
}
+
+ /* Setting scene might require having a dependency graph, with copy on write
+ * we need to make sure we ensure scene has correct color management before
+ * constructing dependency graph.
+ */
+ if (mode != LOAD_UNDO) {
+ IMB_colormanagement_check_file_config(bmain);
+ }
+
BKE_scene_set_background(bmain, curscene);
if (mode != LOAD_UNDO) {
+ /* TODO(sergey): Can this be also move above? */
RE_FreeAllPersistentData();
- IMB_colormanagement_check_file_config(bmain);
}
MEM_freeN(bfd);
@@ -392,7 +417,7 @@ bool BKE_blendfile_read_from_memory(
bfd = BLO_read_from_memory(filebuf, filelength, reports, skip_flags);
if (bfd) {
if (update_defaults)
- BLO_update_defaults_startup_blend(bfd->main);
+ BLO_update_defaults_startup_blend(bfd->main, NULL);
setup_app_data(C, bfd, "<memory2>", reports);
}
else {
@@ -536,6 +561,54 @@ bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *
return ok;
}
+WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath, const void *filebuf, int filelength, ReportList *reports)
+{
+ BlendFileData *bfd;
+ WorkspaceConfigFileData *workspace_config = NULL;
+
+ if (filepath) {
+ bfd = BLO_read_from_file(filepath, reports, BLO_READ_SKIP_USERDEF);
+ }
+ else {
+ bfd = BLO_read_from_memory(filebuf, filelength, 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_HISTORY);
+ bool retval = false;
+
+ BKE_blendfile_write_partial_begin(bmain);
+
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_blendfile_write_partial_tag_ID(&workspace->id, true);
+ }
+
+ if (BKE_blendfile_write_partial(bmain, filepath, fileflags, reports)) {
+ retval = true;
+ }
+
+ BKE_blendfile_write_partial_end(bmain);
+
+ return retval;
+}
+
+void BKE_blendfile_workspace_config_data_free(WorkspaceConfigFileData *workspace_config)
+{
+ BKE_main_free(workspace_config->main);
+ MEM_freeN(workspace_config);
+}
/** \} */
diff --git a/source/blender/blenkernel/intern/bmfont.c b/source/blender/blenkernel/intern/bmfont.c
deleted file mode 100644
index b33b07e3a4f..00000000000
--- a/source/blender/blenkernel/intern/bmfont.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): 04-10-2000 frank.
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- */
-
-/** \file blender/blenkernel/intern/bmfont.c
- * \ingroup bke
- */
-
-
-/**
- * Two external functions:
- *
- * void detectBitmapFont(ImBuf *ibuf)
- * detects if an image buffer contains a bitmap font. It makes the
- * specific bitmap data which is stored in the bitmap invisible to blender.
- *
- * void matrixGlyph(ImBuf *ibuf, unsigned short unicode, *float x 7)
- * returns all the information about the character (unicode) in the floats
- *
- * Room for improvement:
- * add kerning data in the bitmap
- * all calculations in matrixGlyph() are static and could be done during
- * initialization
- */
-
-#include <stdio.h>
-
-#include "MEM_guardedalloc.h"
-#include "IMB_imbuf_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_bmfont.h"
-#include "BKE_bmfont_types.h"
-#include "BKE_global.h"
-
-void printfGlyph(bmGlyph *glyph)
-{
- printf("unicode: %d '%c'\n", glyph->unicode, glyph->unicode);
- printf(" locx: %4d locy: %4d\n", glyph->locx, glyph->locy);
- printf(" sizex: %3d sizey: %3d\n", glyph->sizex, glyph->sizey);
- printf(" ofsx: %3d ofsy: %3d\n", glyph->ofsx, glyph->ofsy);
- printf(" advan: %3d reser: %3d\n", glyph->advance, glyph->reserved);
-}
-
-void calcAlpha(ImBuf *ibuf)
-{
- int i;
- char *rect;
-
- if (ibuf) {
- rect = (char *) ibuf->rect;
- for (i = ibuf->x * ibuf->y; i > 0; i--) {
- rect[3] = MAX3(rect[0], rect[1], rect[2]);
- rect += 4;
- }
- }
-}
-
-void readBitmapFontVersion0(ImBuf *ibuf, unsigned char *rect, int step)
-{
- int glyphcount, bytes, i, index, linelength, ysize;
- unsigned char *buffer;
- bmFont *bmfont;
-
- linelength = ibuf->x * step;
-
- glyphcount = (rect[6 * step] << 8) | rect[7 * step];
- bytes = ((glyphcount - 1) * sizeof(bmGlyph)) + sizeof(bmFont);
-
- ysize = (bytes + (ibuf->x - 1)) / ibuf->x;
-
- if (ysize < ibuf->y) {
- /* we're first going to copy all data into a linear buffer.
- * step can be 4 or 1 bytes, and the data is not sequential because
- * the bitmap was flipped vertically. */
-
- buffer = MEM_mallocN(bytes, "readBitmapFontVersion0:buffer");
-
- index = 0;
- for (i = 0; i < bytes; i++) {
- buffer[i] = rect[index];
- index += step;
- if (index >= linelength) {
- /* we've read one line, no skip to the line *before* that */
- rect -= linelength;
- index -= linelength;
- }
- }
-
- /* we're now going to endian convert the data */
-
- bmfont = MEM_mallocN(bytes, "readBitmapFontVersion0:bmfont");
- index = 0;
-
- /* first read the header */
- bmfont->magic[0] = buffer[index++];
- bmfont->magic[1] = buffer[index++];
- bmfont->magic[2] = buffer[index++];
- bmfont->magic[3] = buffer[index++];
- bmfont->version = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->glyphcount = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->xsize = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->ysize = (buffer[index] << 8) | buffer[index + 1]; index += 2;
-
- for (i = 0; i < bmfont->glyphcount; i++) {
- bmfont->glyphs[i].unicode = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->glyphs[i].locx = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->glyphs[i].locy = (buffer[index] << 8) | buffer[index + 1]; index += 2;
- bmfont->glyphs[i].ofsx = buffer[index++];
- bmfont->glyphs[i].ofsy = buffer[index++];
- bmfont->glyphs[i].sizex = buffer[index++];
- bmfont->glyphs[i].sizey = buffer[index++];
- bmfont->glyphs[i].advance = buffer[index++];
- bmfont->glyphs[i].reserved = buffer[index++];
- if (G.debug & G_DEBUG) {
- printfGlyph(&bmfont->glyphs[i]);
- }
- }
-
- MEM_freeN(buffer);
-
- if (G.debug & G_DEBUG) {
- printf("Oldy = %d Newy = %d\n", ibuf->y, ibuf->y - ysize);
- printf("glyphcount = %d\n", glyphcount);
- printf("bytes = %d\n", bytes);
- }
-
- /* we've read the data from the image. Now we're going
- * to crop the image vertically so only the bitmap data
- * remains visible */
-
- ibuf->y -= ysize;
- ibuf->userdata = bmfont;
- ibuf->userflags |= IB_BITMAPFONT;
-
- if (ibuf->planes < 32) {
- /* we're going to fake alpha here: */
- calcAlpha(ibuf);
- }
- }
- else {
- printf("readBitmapFontVersion0: corrupted bitmapfont\n");
- }
-}
-
-void detectBitmapFont(ImBuf *ibuf)
-{
- unsigned char *rect;
- unsigned short version;
- int i;
-
- if (ibuf != NULL && ibuf->rect != NULL) {
- /* bitmap must have an x size that is a power of two */
- if (is_power_of_two(ibuf->x)) {
- rect = (unsigned char *) (ibuf->rect + (ibuf->x * (ibuf->y - 1)));
- /* printf ("starts with: %s %c %c %c %c\n", rect, rect[0], rect[1], rect[2], rect[3]); */
- if (rect[0] == 'B' && rect[1] == 'F' && rect[2] == 'N' && rect[3] == 'T') {
- /* printf("found 8bit font !\n");
- * round y size down
- * do the 8 bit font stuff. (not yet) */
- }
- else {
- /* we try all 4 possible combinations */
- for (i = 0; i < 4; i++) {
- if (rect[0] == 'B' && rect[4] == 'F' && rect[8] == 'N' && rect[12] == 'T') {
- /* printf("found 24bit font !\n");
- * We're going to parse the file: */
-
- version = (rect[16] << 8) | rect[20];
-
- if (version == 0) {
- readBitmapFontVersion0(ibuf, rect, 4);
- }
- else {
- printf("detectBitmapFont :Unsupported version %d\n", (int)version);
- }
-
- /* on success ibuf->userdata points to the bitmapfont */
- if (ibuf->userdata) {
- break;
- }
- }
- rect++;
- }
- }
- }
- }
-}
-
-int locateGlyph(bmFont *bmfont, unsigned short unicode)
-{
- int min, max, current = 0;
-
- if (bmfont) {
- min = 0;
- max = bmfont->glyphcount;
- while (1) {
- /* look halfway for glyph */
- current = (min + max) >> 1;
-
- if (bmfont->glyphs[current].unicode == unicode) {
- break;
- }
- else if (bmfont->glyphs[current].unicode < unicode) {
- /* have to move up */
- min = current;
- }
- else {
- /* have to move down */
- max = current;
- }
-
- if (max - min <= 1) {
- /* unable to locate glyph */
- current = 0;
- break;
- }
- }
- }
-
- return(current);
-}
-
-void matrixGlyph(
- ImBuf *ibuf, unsigned short unicode,
- float *centerx, float *centery,
- float *sizex, float *sizey,
- float *transx, float *transy,
- float *movex, float *movey,
- float *advance)
-{
- int index;
- bmFont *bmfont;
-
- *centerx = *centery = 0.0;
- *sizex = *sizey = 1.0;
- *transx = *transy = 0.0;
- *movex = *movey = 0.0;
- *advance = 1.0;
-
- if (ibuf) {
- bmfont = ibuf->userdata;
- if (bmfont && (ibuf->userflags & IB_BITMAPFONT)) {
- index = locateGlyph(bmfont, unicode);
- if (index) {
-
- *sizex = (bmfont->glyphs[index].sizex) / (float) (bmfont->glyphs[0].sizex);
- *sizey = (bmfont->glyphs[index].sizey) / (float) (bmfont->glyphs[0].sizey);
-
- *transx = bmfont->glyphs[index].locx / (float) ibuf->x;
- *transy = (ibuf->y - bmfont->glyphs[index].locy) / (float) ibuf->y;
-
- *centerx = bmfont->glyphs[0].locx / (float) ibuf->x;
- *centery = (ibuf->y - bmfont->glyphs[0].locy) / (float) ibuf->y;
-
- /* 2.0 units is the default size of an object */
-
- *movey = 1.0f - *sizey + 2.0f * (bmfont->glyphs[index].ofsy - bmfont->glyphs[0].ofsy) / (float) bmfont->glyphs[0].sizey;
- *movex = *sizex - 1.0f + 2.0f * (bmfont->glyphs[index].ofsx - bmfont->glyphs[0].ofsx) / (float) bmfont->glyphs[0].sizex;
-
- *advance = 2.0f * bmfont->glyphs[index].advance / (float) bmfont->glyphs[0].advance;
-
- // printfGlyph(&bmfont->glyphs[index]);
- // printf("%c %d %0.5f %0.5f %0.5f %0.5f %0.5f\n", unicode, index, *sizex, *sizey, *transx, *transy, *advance);
- }
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index 10f7a3b9457..e88dcc71b2e 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -132,6 +132,7 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val,
if (eff == NULL && gabr->ob) {
memset(&temp_eff, 0, sizeof(EffectorCache));
temp_eff.ob = gabr->ob;
+ temp_eff.depsgraph = bbd->sim->depsgraph;
temp_eff.scene = bbd->sim->scene;
eff = &temp_eff;
get_effector_data(eff, &efd, &epoint, 0);
@@ -1264,7 +1265,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa)
/* account for effectors */
pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
- pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
+ BKE_effectors_apply(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
if (ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
float length = normalize_v3(force);
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 0b191e1f69b..88a4b7905ef 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -478,13 +478,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
} \
} (void)0
- /* do via modifiers instead */
-#if 0
- if (ob->fluidsimSettings) {
- rewrite_path_fixed(ob->fluidsimSettings->surfdataPath, visit_cb, absbase, bpath_user_data);
- }
-#endif
-
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Fluidsim) {
FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
@@ -513,7 +506,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
}
if (ob->soft) {
- BPATH_TRAVERSE_POINTCACHE(ob->soft->ptcaches);
+ BPATH_TRAVERSE_POINTCACHE(ob->soft->shared->ptcaches);
}
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
@@ -588,14 +581,6 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
}
break;
}
- case ID_TE:
- {
- Tex *tex = (Tex *)id;
- if (tex->type == TEX_VOXELDATA && TEX_VD_IS_SOURCE_PATH(tex->vd->file_format)) {
- rewrite_path_fixed(tex->vd->source_path, visit_cb, absbase, bpath_user_data);
- }
- break;
- }
case ID_SCE:
{
Scene *scene = (Scene *)id;
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 5b76d75f261..39266eed6fe 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -29,6 +29,7 @@
#include "DNA_brush_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
@@ -36,6 +37,7 @@
#include "BKE_brush.h"
#include "BKE_colortools.h"
+#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -129,6 +131,7 @@ static void brush_defaults(Brush *brush)
brush->stencil_dimension[0] = 256;
brush->stencil_dimension[1] = 256;
+
}
/* Datablock add/copy/free/make_local */
@@ -164,6 +167,374 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
return brush;
}
+/* add grease pencil settings */
+void BKE_brush_init_gpencil_settings(Brush *brush)
+{
+ if (brush->gpencil_settings == NULL) {
+ brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings");
+ }
+
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->flag = 0;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+
+ /* curves */
+ brush->gpencil_settings->curve_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ brush->gpencil_settings->curve_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+/* add a new gp-brush */
+Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name)
+{
+ Brush *brush;
+ Paint *paint = &ts->gp_paint->paint;
+ brush = BKE_brush_add(bmain, name, OB_MODE_GPENCIL_PAINT);
+
+ BKE_paint_brush_set(paint, brush);
+ id_us_min(&brush->id);
+
+ brush->size = 3;
+
+ /* grease pencil basic settings */
+ BKE_brush_init_gpencil_settings(brush);
+
+ /* return brush */
+ return brush;
+}
+
+/* grease pencil cumapping->preset */
+typedef enum eGPCurveMappingPreset {
+ GPCURVE_PRESET_PENCIL = 0,
+ GPCURVE_PRESET_INK = 1,
+ GPCURVE_PRESET_INKNOISE = 2,
+} eGPCurveMappingPreset;
+
+static void brush_gpencil_curvemap_reset(CurveMap *cuma, int preset)
+{
+ if (cuma->curve)
+ MEM_freeN(cuma->curve);
+
+ cuma->totpoint = 3;
+ cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__);
+
+ switch (preset) {
+ case GPCURVE_PRESET_PENCIL:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.75115f;
+ cuma->curve[1].y = 0.25f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INK:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63448f;
+ cuma->curve[1].y = 0.375f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ case GPCURVE_PRESET_INKNOISE:
+ cuma->curve[0].x = 0.0f;
+ cuma->curve[0].y = 0.0f;
+ cuma->curve[1].x = 0.63134f;
+ cuma->curve[1].y = 0.3625f;
+ cuma->curve[2].x = 1.0f;
+ cuma->curve[2].y = 1.0f;
+ break;
+ }
+
+ if (cuma->table) {
+ MEM_freeN(cuma->table);
+ cuma->table = NULL;
+ }
+}
+
+/* create a set of grease pencil presets */
+void BKE_brush_gpencil_presets(bContext *C)
+{
+#define SMOOTH_STROKE_RADIUS 40
+#define SMOOTH_STROKE_FACTOR 0.9f
+
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Paint *paint = &ts->gp_paint->paint;
+ Main *bmain = CTX_data_main(C);
+
+ Brush *brush, *deft;
+ CurveMapping *custom_curve;
+
+ /* Pencil brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
+ brush->size = 25.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 0.6f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Pen brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
+ deft = brush; /* save default brush */
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Ink brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.6f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INK);
+
+ /* Ink Noise brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
+ brush->size = 60.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.7f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 2;
+ brush->gpencil_settings->thick_smoothfac = 0.5f;
+ brush->gpencil_settings->thick_smoothlvl = 2;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Curve */
+ custom_curve = brush->gpencil_settings->curve_sensitivity;
+ curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
+ curvemapping_initialize(custom_curve);
+ brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INKNOISE);
+
+ /* Block Basic brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
+ brush->size = 150.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 0.7f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+
+ brush->gpencil_settings->draw_random_press = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = 0.0f;
+ brush->gpencil_settings->draw_angle_factor = 0.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.0f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 0;
+ brush->gpencil_settings->draw_random_sub = 0;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Marker brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
+ brush->size = 80.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
+ brush->gpencil_settings->draw_random_press = 0.374f;
+ brush->gpencil_settings->draw_random_strength = 0.0f;
+
+ brush->gpencil_settings->draw_jitter = 0.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+
+ brush->gpencil_settings->draw_angle = M_PI_4; /* 45 degrees */
+ brush->gpencil_settings->draw_angle_factor = 1.0f;
+
+ brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+ brush->gpencil_settings->draw_random_sub = 0.0f;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
+ brush->gpencil_tool = GPAINT_TOOL_DRAW;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ /* Fill brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
+ brush->size = 1.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->draw_sensitivity = 1.0f;
+ brush->gpencil_settings->fill_leak = 3;
+ brush->gpencil_settings->fill_threshold = 0.1f;
+ brush->gpencil_settings->fill_simplylvl = 1;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
+ brush->gpencil_tool = GPAINT_TOOL_FILL;
+
+ brush->gpencil_settings->draw_smoothfac = 0.1f;
+ brush->gpencil_settings->draw_smoothlvl = 1;
+ brush->gpencil_settings->thick_smoothfac = 1.0f;
+ brush->gpencil_settings->thick_smoothlvl = 3;
+ brush->gpencil_settings->draw_subdivide = 1;
+
+ brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
+ brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
+
+ brush->gpencil_settings->draw_strength = 1.0f;
+
+ /* Soft Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
+ brush->gpencil_settings->era_strength_f = 100.0f;
+ brush->gpencil_settings->era_thickness_f = 0.10f;
+
+ /* Hard Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Vertex");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
+
+ /* Stroke Eraser brush */
+ brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
+ brush->size = 30.0f;
+ brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
+ brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
+ brush->gpencil_tool = GPAINT_TOOL_ERASE;
+ brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
+
+ /* set default brush */
+ BKE_paint_brush_set(paint, deft);
+
+}
+
+void BKE_brush_update_material(Main *bmain, Material *ma, Brush *exclude_brush)
+{
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if ((exclude_brush != NULL) && (brush == exclude_brush)) {
+ continue;
+ }
+
+ if (brush->gpencil_settings != NULL) {
+ BrushGpencilSettings *gpencil_settings = brush->gpencil_settings;
+ if (((gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) == 0) &&
+ (gpencil_settings->material != ma))
+ {
+ gpencil_settings->material = ma;
+ }
+ }
+ }
+}
+
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
{
Brush *brush;
@@ -197,6 +568,12 @@ void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *bru
}
brush_dst->curve = curvemapping_copy(brush_src->curve);
+ if (brush_src->gpencil_settings != NULL) {
+ brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings);
+ brush_dst->gpencil_settings->curve_sensitivity = curvemapping_copy(brush_src->gpencil_settings->curve_sensitivity);
+ brush_dst->gpencil_settings->curve_strength = curvemapping_copy(brush_src->gpencil_settings->curve_strength);
+ brush_dst->gpencil_settings->curve_jitter = curvemapping_copy(brush_src->gpencil_settings->curve_jitter);
+ }
/* enable fake user by default */
id_fake_user_set(&brush_dst->id);
@@ -215,11 +592,18 @@ void BKE_brush_free(Brush *brush)
if (brush->icon_imbuf) {
IMB_freeImBuf(brush->icon_imbuf);
}
-
curvemapping_free(brush->curve);
+ if (brush->gpencil_settings != NULL) {
+ curvemapping_free(brush->gpencil_settings->curve_sensitivity);
+ curvemapping_free(brush->gpencil_settings->curve_strength);
+ curvemapping_free(brush->gpencil_settings->curve_jitter);
+ MEM_SAFE_FREE(brush->gpencil_settings);
+ }
+
MEM_SAFE_FREE(brush->gradient);
+
BKE_previewimg_free(&(brush->preview));
}
diff --git a/source/blender/blenkernel/intern/bullet.c b/source/blender/blenkernel/intern/bullet.c
deleted file mode 100644
index 9630ee389fa..00000000000
--- a/source/blender/blenkernel/intern/bullet.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/bullet.c
- * \ingroup bke
- */
-
-
-#include "MEM_guardedalloc.h"
-
-/* types */
-#include "DNA_object_force_types.h" /* here is the softbody struct */
-
-#include "BKE_bullet.h"
-
-
-/* ************ Object level, exported functions *************** */
-
-/* allocates and initializes general main data */
-BulletSoftBody *bsbNew(void)
-{
- BulletSoftBody *bsb;
-
- bsb = MEM_callocN(sizeof(BulletSoftBody), "bulletsoftbody");
-
- bsb->flag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT;
- bsb->linStiff = 0.5f;
- bsb->angStiff = 1.0f;
- bsb->volume = 1.0f;
-
-
- bsb->viterations = 0;
- bsb->piterations = 2;
- bsb->diterations = 0;
- bsb->citerations = 4;
-
- bsb->kSRHR_CL = 0.1f;
- bsb->kSKHR_CL = 1.f;
- bsb->kSSHR_CL = 0.5f;
- bsb->kSR_SPLT_CL = 0.5f;
-
- bsb->kSK_SPLT_CL = 0.5f;
- bsb->kSS_SPLT_CL = 0.5f;
- bsb->kVCF = 1;
- bsb->kDP = 0;
-
- bsb->kDG = 0;
- bsb->kLF = 0;
- bsb->kPR = 0;
- bsb->kVC = 0;
-
- bsb->kDF = 0.2f;
- bsb->kMT = 0.05;
- bsb->kCHR = 1.0f;
- bsb->kKHR = 0.1f;
-
- bsb->kSHR = 1.0f;
- bsb->kAHR = 0.7f;
-
- bsb->collisionflags = 0;
- //bsb->collisionflags = OB_BSB_COL_CL_RS + OB_BSB_COL_CL_SS;
- bsb->numclusteriterations = 64;
- bsb->welding = 0.f;
-
- return bsb;
-}
-
-/* frees all */
-void bsbFree(BulletSoftBody *bsb)
-{
- /* no internal data yet */
- MEM_freeN(bsb);
-}
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index 151d697d891..5c27b1b6207 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -34,6 +34,7 @@
#include <math.h>
#include <assert.h>
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
@@ -41,8 +42,10 @@
#include "BLI_math.h"
#include "BLI_threads.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_bvhutils.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "MEM_guardedalloc.h"
@@ -423,7 +426,8 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
const MVert *vert, const int verts_num,
const BLI_bitmap *verts_mask, int verts_num_active)
{
- BLI_assert(vert != NULL);
+ BVHTree *tree = NULL;
+
if (verts_mask) {
BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num));
}
@@ -431,17 +435,19 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree(
verts_num_active = verts_num;
}
- BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
+ if (verts_num_active) {
+ tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (int i = 0; i < verts_num; i++) {
- if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
- continue;
+ if (tree) {
+ for (int i = 0; i < verts_num; i++) {
+ if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) {
+ continue;
+ }
+ BLI_bvhtree_insert(tree, i, vert[i].co, 1);
}
- BLI_bvhtree_insert(tree, i, vert[i].co, 1);
+ BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
+ BLI_bvhtree_balance(tree);
}
- BLI_assert(BLI_bvhtree_get_len(tree) == verts_num_active);
- BLI_bvhtree_balance(tree);
}
return tree;
@@ -463,7 +469,6 @@ static void bvhtree_from_mesh_verts_setup_data(
data->vert = vert;
data->vert_allocated = vert_allocated;
- //data->face = DM_get_tessface_array(dm, &data->face_allocated); /* XXX WHY???? */
}
/* Builds a bvh tree where nodes are the vertices of the given em */
@@ -489,12 +494,39 @@ BVHTree *bvhtree_from_editmesh_verts_ex(
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache)
{
- return bvhtree_from_editmesh_verts_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
+ if (bvh_cache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data->cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data->cached = bvhcache_find(
+ *bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree);
+ if (data->cached == false) {
+ data->tree = bvhtree_from_editmesh_verts_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ bvh_cache, data->tree, BVHTREE_FROM_EM_VERTS);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ data->tree = bvhtree_from_editmesh_verts_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+ }
+
+ return data->tree;
}
/**
@@ -567,29 +599,31 @@ static BVHTree *bvhtree_from_mesh_edges_create_tree(
const BLI_bitmap *edges_mask, int edges_num_active,
float epsilon, int tree_type, int axis)
{
+ BVHTree *tree = NULL;
+
if (edges_mask) {
BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num));
}
else {
edges_num_active = edge_num;
}
- BLI_assert(vert != NULL);
- BLI_assert(edge != NULL);
- /* Create a bvh-tree of the given target */
- BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
- if (tree) {
- for (int i = 0; i < edge_num; i++) {
- if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
- continue;
- }
- float co[2][3];
- copy_v3_v3(co[0], vert[edge[i].v1].co);
- copy_v3_v3(co[1], vert[edge[i].v2].co);
+ if (edges_num_active) {
+ /* Create a bvh-tree of the given target */
+ tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis);
+ if (tree) {
+ for (int i = 0; i < edge_num; i++) {
+ if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) {
+ continue;
+ }
+ float co[2][3];
+ copy_v3_v3(co[0], vert[edge[i].v1].co);
+ copy_v3_v3(co[1], vert[edge[i].v2].co);
- BLI_bvhtree_insert(tree, i, co[0], 2);
+ BLI_bvhtree_insert(tree, i, co[0], 2);
+ }
+ BLI_bvhtree_balance(tree);
}
- BLI_bvhtree_balance(tree);
}
return tree;
@@ -641,12 +675,39 @@ BVHTree *bvhtree_from_editmesh_edges_ex(
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, BMEditMesh *em,
- float epsilon, int tree_type, int axis)
+ float epsilon, int tree_type, int axis, BVHCache **bvh_cache)
{
- return bvhtree_from_editmesh_edges_ex(
- data, em,
- NULL, -1,
- epsilon, tree_type, axis);
+ if (bvh_cache) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
+ data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
+ BLI_rw_mutex_unlock(&cache_rwlock);
+
+ if (data->cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data->cached = bvhcache_find(
+ *bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree);
+ if (data->cached == false) {
+ data->tree = bvhtree_from_editmesh_edges_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ bvh_cache, data->tree, BVHTREE_FROM_EM_EDGES);
+ }
+ BLI_rw_mutex_unlock(&cache_rwlock);
+ }
+ }
+ else {
+ data->tree = bvhtree_from_editmesh_edges_ex(
+ data, em,
+ NULL, -1,
+ epsilon, tree_type, axis);
+ }
+
+ return data->tree;
}
/**
@@ -833,22 +894,21 @@ static BVHTree *bvhtree_from_mesh_looptri_create_tree(
const BLI_bitmap *looptri_mask, int looptri_num_active)
{
BVHTree *tree = NULL;
- int i;
- if (looptri_num) {
- if (looptri_mask) {
- BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
- }
- else {
- looptri_num_active = looptri_num;
- }
+ if (looptri_mask) {
+ BLI_assert(IN_RANGE_INCL(looptri_num_active, 0, looptri_num));
+ }
+ else {
+ looptri_num_active = looptri_num;
+ }
+ if (looptri_num_active) {
/* Create a bvh-tree of the given target */
/* printf("%s: building BVH, total=%d\n", __func__, numFaces); */
tree = BLI_bvhtree_new(looptri_num_active, epsilon, tree_type, axis);
if (tree) {
if (vert && looptri) {
- for (i = 0; i < looptri_num; i++) {
+ for (int i = 0; i < looptri_num; i++) {
float co[3][3];
if (looptri_mask && !BLI_BITMAP_TEST_BOOL(looptri_mask, i)) {
continue;
@@ -902,23 +962,23 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(
/* BMESH specific check that we have tessfaces,
* we _could_ tessellate here but rather not - campbell */
- BVHTree *tree;
+ BVHTree *tree = NULL;
if (bvhCache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
+ bool in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
- if (tree == NULL) {
+ if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI);
- if (tree == NULL) {
+ in_cache = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI, &tree);
+ if (in_cache == false) {
tree = bvhtree_from_editmesh_looptri_create_tree(
epsilon, tree_type, axis,
em, em->tottri, looptri_mask, looptri_num_active);
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
- }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI);
+
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
@@ -976,189 +1036,233 @@ BVHTree *bvhtree_from_mesh_looptri_ex(
return tree;
}
+static BLI_bitmap *loose_verts_map_get(
+ const MEdge *medge, int edges_num,
+ const MVert *UNUSED(mvert), int verts_num,
+ int *r_loose_vert_num)
+{
+ BLI_bitmap *loose_verts_mask = BLI_BITMAP_NEW(verts_num, __func__);
+ BLI_BITMAP_SET_ALL(loose_verts_mask, true, verts_num);
+
+ const MEdge *e = medge;
+ int num_linked_verts = 0;
+ for (;edges_num--; e++) {
+ if (BLI_BITMAP_TEST(loose_verts_mask, e->v1)) {
+ BLI_BITMAP_DISABLE(loose_verts_mask, e->v1);
+ num_linked_verts++;
+ }
+ if (BLI_BITMAP_TEST(loose_verts_mask, e->v2)) {
+ BLI_BITMAP_DISABLE(loose_verts_mask, e->v2);
+ num_linked_verts++;
+ }
+ }
+
+ *r_loose_vert_num = verts_num - num_linked_verts;
+
+ return loose_verts_mask;
+}
+
+static BLI_bitmap *loose_edges_map_get(
+ const MEdge *medge, const int edges_len,
+ int *r_loose_edge_len)
+{
+ BLI_bitmap *loose_edges_mask = BLI_BITMAP_NEW(edges_len, __func__);
+
+ int loose_edges_len = 0;
+ const MEdge *e = medge;
+ for (int i = 0; i < edges_len; i++, e++) {
+ if (e->flag & ME_LOOSEEDGE) {
+ BLI_BITMAP_ENABLE(loose_edges_mask, i);
+ loose_edges_len++;
+ }
+ else {
+ BLI_BITMAP_DISABLE(loose_edges_mask, i);
+ }
+ }
+
+ *r_loose_edge_len = loose_edges_len;
+
+ return loose_edges_mask;
+}
+
/**
* Builds or queries a bvhcache for the cache bvhtree of the request type.
*/
-BVHTree *bvhtree_from_mesh_get(
- struct BVHTreeFromMesh *data, struct DerivedMesh *dm,
+BVHTree *BKE_bvhtree_from_mesh_get(
+ struct BVHTreeFromMesh *data, struct Mesh *mesh,
const int type, const int tree_type)
{
- BVHTree *tree = NULL;
-
- BVHTree_NearestPointCallback nearest_callback = NULL;
- BVHTree_RayCastCallback raycast_callback = NULL;
-
- MVert *mvert = NULL;
- MEdge *medge = NULL;
- MFace *mface = NULL;
- MLoop *mloop = NULL;
- const MLoopTri *looptri = NULL;
- bool vert_allocated = false;
- bool edge_allocated = false;
- bool face_allocated = false;
- bool loop_allocated = false;
- bool looptri_allocated = false;
+ struct BVHTreeFromMesh data_cp = {0};
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
- tree = bvhcache_find(dm->bvhCache, type);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
BLI_rw_mutex_unlock(&cache_rwlock);
+ if (data_cp.cached && data_cp.tree == NULL) {
+ memset(data, 0, sizeof(*data));
+ return data_cp.tree;
+ }
+
switch (type) {
case BVHTREE_FROM_VERTS:
- raycast_callback = mesh_verts_spherecast;
+ case BVHTREE_FROM_LOOSEVERTS:
+ data_cp.raycast_callback = mesh_verts_spherecast;
- mvert = DM_get_vert_array(dm, &vert_allocated);
+ data_cp.vert = mesh->mvert;
- if (tree == NULL) {
- /* Not in cache */
+ if (data_cp.cached == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_VERTS);
- if (tree == NULL) {
- tree = bvhtree_from_mesh_verts_create_tree(
- 0.0, tree_type, 6, mvert, dm->getNumVerts(dm), NULL, -1);
-
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_VERTS);
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, type, &data_cp.tree);
+
+ if (data_cp.cached == false) {
+ BLI_bitmap *loose_verts_mask = NULL;
+ int loose_vert_len = -1;
+ int verts_len = mesh->totvert;
+
+ if (type == BVHTREE_FROM_LOOSEVERTS) {
+ loose_verts_mask = loose_verts_map_get(
+ mesh->medge, mesh->totedge, data_cp.vert,
+ verts_len, &loose_vert_len);
+ }
+
+ data_cp.tree = bvhtree_from_mesh_verts_create_tree(
+ 0.0, tree_type, 6, data_cp.vert, verts_len,
+ loose_verts_mask, loose_vert_len);
+
+ if (loose_verts_mask != NULL) {
+ MEM_freeN(loose_verts_mask);
}
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
case BVHTREE_FROM_EDGES:
- nearest_callback = mesh_edges_nearest_point;
- raycast_callback = mesh_edges_spherecast;
+ case BVHTREE_FROM_LOOSEEDGES:
+ data_cp.nearest_callback = mesh_edges_nearest_point;
+ data_cp.raycast_callback = mesh_edges_spherecast;
- mvert = DM_get_vert_array(dm, &vert_allocated);
- medge = DM_get_edge_array(dm, &edge_allocated);
+ data_cp.vert = mesh->mvert;
+ data_cp.edge = mesh->medge;
- if (tree == NULL) {
- /* Not in cache */
+ if (data_cp.cached == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES);
- if (tree == NULL) {
- tree = bvhtree_from_mesh_edges_create_tree(
- mvert, medge, dm->getNumEdges(dm),
- NULL, -1, 0.0, tree_type, 6);
-
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES);
+ data_cp.cached = bvhcache_find(mesh->runtime.bvh_cache, type, &data_cp.tree);
+ if (data_cp.cached == false) {
+ BLI_bitmap *loose_edges_mask = NULL;
+ int loose_edges_len = -1;
+ int edges_len = mesh->totedge;
+
+ if (type == BVHTREE_FROM_LOOSEEDGES) {
+ loose_edges_mask = loose_edges_map_get(
+ data_cp.edge, edges_len, &loose_edges_len);
}
+
+ data_cp.tree = bvhtree_from_mesh_edges_create_tree(
+ data_cp.vert, data_cp.edge, edges_len,
+ loose_edges_mask, loose_edges_len, 0.0, tree_type, 6);
+
+ if (loose_edges_mask != NULL) {
+ MEM_freeN(loose_edges_mask);
+ }
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(&mesh->runtime.bvh_cache, data_cp.tree, type);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
case BVHTREE_FROM_FACES:
- nearest_callback = mesh_faces_nearest_point;
- raycast_callback = mesh_faces_spherecast;
+ data_cp.nearest_callback = mesh_faces_nearest_point;
+ data_cp.raycast_callback = mesh_faces_spherecast;
- mvert = DM_get_vert_array(dm, &vert_allocated);
- mface = DM_get_tessface_array(dm, &face_allocated);
+ data_cp.vert = mesh->mvert;
+ data_cp.face = mesh->mface;
- if (tree == NULL) {
- /* Not in cache */
+ if (data_cp.cached == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_FACES);
- if (tree == NULL) {
- int numFaces = dm->getNumTessFaces(dm);
- BLI_assert(!(numFaces == 0 && dm->getNumPolys(dm) != 0));
-
- tree = bvhtree_from_mesh_faces_create_tree(
- 0.0, tree_type, 6, mvert, mface, numFaces, NULL, -1);
-
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_FACES);
- }
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, BVHTREE_FROM_FACES, &data_cp.tree);
+ if (data_cp.cached == false) {
+ int num_faces = mesh->totface;
+ BLI_assert(!(num_faces == 0 && mesh->totpoly != 0));
+
+ data_cp.tree = bvhtree_from_mesh_faces_create_tree(
+ 0.0, tree_type, 6, data_cp.vert,
+ data_cp.face, num_faces, NULL, -1);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_FACES);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
case BVHTREE_FROM_LOOPTRI:
- nearest_callback = mesh_looptri_nearest_point;
- raycast_callback = mesh_looptri_spherecast;
+ data_cp.nearest_callback = mesh_looptri_nearest_point;
+ data_cp.raycast_callback = mesh_looptri_spherecast;
- mvert = DM_get_vert_array(dm, &vert_allocated);
- mloop = DM_get_loop_array(dm, &loop_allocated);
- looptri = dm->getLoopTriArray(dm);
+ data_cp.vert = mesh->mvert;
+ data_cp.loop = mesh->mloop;
- if (tree == NULL) {
- /* Not in cache */
- BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
- tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI);
- if (tree == NULL) {
- int looptri_num = dm->getNumLoopTri(dm);
+ /* TODO: store looptris somewhere? */
+ data_cp.looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ if (data_cp.cached == false) {
+ BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
+ data_cp.cached = bvhcache_find(
+ mesh->runtime.bvh_cache, BVHTREE_FROM_LOOPTRI, &data_cp.tree);
+ if (data_cp.cached == false) {
+ int looptri_num = BKE_mesh_runtime_looptri_len(mesh);
/* this assert checks we have looptris,
* if not caller should use DM_ensure_looptri() */
- BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0));
+ BLI_assert(!(looptri_num == 0 && mesh->totpoly != 0));
- tree = bvhtree_from_mesh_looptri_create_tree(
+ data_cp.tree = bvhtree_from_mesh_looptri_create_tree(
0.0, tree_type, 6,
- mvert, mloop, looptri, looptri_num, NULL, -1);
- if (tree) {
- /* Save on cache for later use */
- /* printf("BVHTree built and saved on cache\n"); */
- bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_LOOPTRI);
- }
+ data_cp.vert, data_cp.loop,
+ data_cp.looptri, looptri_num, NULL, -1);
+
+ /* Save on cache for later use */
+ /* printf("BVHTree built and saved on cache\n"); */
+ bvhcache_insert(
+ &mesh->runtime.bvh_cache, data_cp.tree, BVHTREE_FROM_LOOPTRI);
}
BLI_rw_mutex_unlock(&cache_rwlock);
}
break;
+ case BVHTREE_FROM_EM_VERTS:
+ case BVHTREE_FROM_EM_EDGES:
+ case BVHTREE_FROM_EM_LOOPTRI:
+ BLI_assert(false);
+ break;
}
- if (tree != NULL) {
+ if (data_cp.tree != NULL) {
#ifdef DEBUG
- if (BLI_bvhtree_get_tree_type(tree) != tree_type) {
- printf("tree_type %d obtained instead of %d\n", BLI_bvhtree_get_tree_type(tree), tree_type);
+ if (BLI_bvhtree_get_tree_type(data_cp.tree) != tree_type) {
+ printf("tree_type %d obtained instead of %d\n",
+ BLI_bvhtree_get_tree_type(data_cp.tree), tree_type);
}
#endif
- data->tree = tree;
-
- data->nearest_callback = nearest_callback;
- data->raycast_callback = raycast_callback;
-
- data->vert = mvert;
- data->edge = medge;
- data->face = mface;
- data->loop = mloop;
- data->looptri = looptri;
- data->vert_allocated = vert_allocated;
- data->edge_allocated = edge_allocated;
- data->face_allocated = face_allocated;
- data->loop_allocated = loop_allocated;
- data->looptri_allocated = looptri_allocated;
-
- data->cached = true;
+ data_cp.cached = true;
+ memcpy(data, &data_cp, sizeof(*data));
}
else {
- if (vert_allocated) {
- MEM_freeN(mvert);
- }
- if (edge_allocated) {
- MEM_freeN(medge);
- }
- if (face_allocated) {
- MEM_freeN(mface);
- }
- if (loop_allocated) {
- MEM_freeN(mloop);
- }
- if (looptri_allocated) {
- MEM_freeN((void *)looptri);
- }
-
+ free_bvhtree_from_mesh(&data_cp);
memset(data, 0, sizeof(*data));
}
- return tree;
+ return data_cp.tree;
}
/** \} */
@@ -1216,16 +1320,17 @@ typedef struct BVHCacheItem {
/**
* Queries a bvhcache for the cache bvhtree of the request type
*/
-BVHTree *bvhcache_find(BVHCache *cache, int type)
+bool bvhcache_find(const BVHCache *cache, int type, BVHTree **r_tree)
{
while (cache) {
const BVHCacheItem *item = cache->link;
if (item->type == type) {
- return item->tree;
+ *r_tree = item->tree;
+ return true;
}
cache = cache->next;
}
- return NULL;
+ return false;
}
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
@@ -1251,11 +1356,9 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
{
BVHCacheItem *item = NULL;
- assert(tree != NULL);
- assert(bvhcache_find(*cache_p, type) == NULL);
+ assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false);
item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
- assert(item != NULL);
item->type = type;
item->tree = tree;
@@ -1264,13 +1367,8 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type)
}
/**
- * inits and frees a bvhcache
+ * frees a bvhcache
*/
-void bvhcache_init(BVHCache **cache_p)
-{
- *cache_p = NULL;
-}
-
static void bvhcacheitem_free(void *_item)
{
BVHCacheItem *item = (BVHCacheItem *)_item;
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 5f7759c7b55..c7d7a3a98eb 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -89,13 +89,22 @@ void BKE_cachefile_free(CacheFile *cache_file)
{
BKE_animdata_free((ID *)cache_file, false);
+ if (cache_file->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
+
+ if (cache_file->handle) {
#ifdef WITH_ALEMBIC
- ABC_free_handle(cache_file->handle);
+ ABC_free_handle(cache_file->handle);
#endif
-
+ cache_file->handle = NULL;
+ }
if (cache_file->handle_mutex) {
BLI_mutex_free(cache_file->handle_mutex);
+ cache_file->handle_mutex = NULL;
}
+
BLI_freelistN(&cache_file->object_paths);
}
@@ -110,8 +119,14 @@ void BKE_cachefile_free(CacheFile *cache_file)
void BKE_cachefile_copy_data(
Main *UNUSED(bmain), CacheFile *cache_file_dst, const CacheFile *UNUSED(cache_file_src), const int UNUSED(flag))
{
+ if (cache_file_dst->id.tag & LIB_TAG_NO_MAIN) {
+ /* CoW/no-main copies reuse the existing ArchiveReader and mutex */
+ return;
+ }
+
cache_file_dst->handle = NULL;
- BLI_listbase_clear(&cache_file_dst->object_paths);
+ cache_file_dst->handle_mutex = NULL;
+ BLI_duplicatelist(&cache_file_dst->object_paths, &cache_file_dst->object_paths);
}
CacheFile *BKE_cachefile_copy(Main *bmain, const CacheFile *cache_file)
@@ -153,20 +168,24 @@ void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
BLI_mutex_lock(cache_file->handle_mutex);
if (cache_file->handle == NULL) {
+ /* Assigning to a CoW copy is a bad idea; assign to the original instead. */
+ BLI_assert((cache_file->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
BKE_cachefile_reload(bmain, cache_file);
}
BLI_mutex_unlock(cache_file->handle_mutex);
}
-void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps)
+void BKE_cachefile_update_frame(
+ Main *bmain, struct Depsgraph *depsgraph, Scene *scene,
+ const float ctime, const float fps)
{
CacheFile *cache_file;
char filename[FILE_MAX];
for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
/* Execute drivers only, as animation has already been done. */
- BKE_animsys_evaluate_animdata(scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
if (!cache_file->is_sequence) {
continue;
@@ -175,7 +194,7 @@ void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, co
const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
- BKE_cachefile_clean(scene, cache_file);
+ BKE_cachefile_clean(bmain, cache_file);
#ifdef WITH_ALEMBIC
ABC_free_handle(cache_file->handle);
cache_file->handle = ABC_create_handle(filename, NULL);
@@ -215,11 +234,9 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f
}
/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */
-void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file)
+void BKE_cachefile_clean(struct Main *bmain, CacheFile *cache_file)
{
- for (Base *base = scene->base.first; base; base = base->next) {
- Object *ob = base->object;
-
+ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache);
if (md) {
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index bda26c95815..54ce0d3a903 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -40,6 +40,7 @@
#include "DNA_ID.h"
#include "BLI_math.h"
+#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -47,6 +48,7 @@
#include "BKE_animsys.h"
#include "BKE_camera.h"
#include "BKE_object.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
@@ -54,7 +56,9 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "GPU_compositing.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
/****************************** Camera Datablock *****************************/
@@ -62,17 +66,18 @@ void BKE_camera_init(Camera *cam)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(cam, id));
- cam->lens = 35.0f;
+ cam->lens = 50.0f;
cam->sensor_x = DEFAULT_SENSOR_WIDTH;
cam->sensor_y = DEFAULT_SENSOR_HEIGHT;
cam->clipsta = 0.1f;
- cam->clipend = 100.0f;
+ cam->clipend = 1000.0f;
cam->drawsize = 0.5f;
cam->ortho_scale = 6.0;
cam->flag |= CAM_SHOWPASSEPARTOUT;
cam->passepartalpha = 0.5f;
- GPU_fx_compositor_init_dof_settings(&cam->gpu_dof);
+ cam->gpu_dof.fstop = 128.0f;
+ cam->gpu_dof.ratio = 1.0f;
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
@@ -100,9 +105,9 @@ void *BKE_camera_add(Main *bmain, const char *name)
*
* \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *UNUSED(cam_dst), const Camera *UNUSED(cam_src), const int UNUSED(flag))
+void BKE_camera_copy_data(Main *UNUSED(bmain), Camera *cam_dst, const Camera *cam_src, const int UNUSED(flag))
{
- /* Nothing to do! */
+ BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images);
}
Camera *BKE_camera_copy(Main *bmain, const Camera *cam)
@@ -120,22 +125,13 @@ void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local)
/** Free (or release) any data used by this camera (does not free the camera itself). */
void BKE_camera_free(Camera *ca)
{
+ BLI_freelistN(&ca->bg_images);
+
BKE_animdata_free((ID *)ca, false);
}
/******************************** Camera Usage *******************************/
-void BKE_camera_object_mode(RenderData *rd, Object *cam_ob)
-{
- rd->mode &= ~(R_ORTHO | R_PANORAMA);
-
- if (cam_ob && cam_ob->type == OB_CAMERA) {
- Camera *cam = cam_ob->data;
- if (cam->type == CAM_ORTHO) rd->mode |= R_ORTHO;
- if (cam->type == CAM_PANO) rd->mode |= R_PANORAMA;
- }
-}
-
/* get the camera's dof value, takes the dof object into account */
float BKE_camera_object_dof_distance(Object *ob)
{
@@ -143,15 +139,10 @@ float BKE_camera_object_dof_distance(Object *ob)
if (ob->type != OB_CAMERA)
return 0.0f;
if (cam->dof_ob) {
-#if 0
- /* too simple, better to return the distance on the view axis only */
- return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]);
-#else
float view_dir[3], dof_dir[3];
normalize_v3_v3(view_dir, ob->obmat[2]);
sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof_ob->obmat[3]);
return fabsf(dot_v3v3(view_dir, dof_dir));
-#endif
}
return cam->YF_dofdist;
}
@@ -237,7 +228,7 @@ void BKE_camera_params_from_object(CameraParams *params, const Object *ob)
}
}
-void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, const RegionView3D *rv3d)
+void BKE_camera_params_from_view3d(CameraParams *params, Depsgraph *depsgraph, const View3D *v3d, const RegionView3D *rv3d)
{
/* common */
params->lens = v3d->lens;
@@ -246,7 +237,8 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons
if (rv3d->persp == RV3D_CAMOB) {
/* camera view */
- BKE_camera_params_from_object(params, v3d->camera);
+ const Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, v3d->camera);
+ BKE_camera_params_from_object(params, ob_camera_eval);
params->zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom);
@@ -281,10 +273,7 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
float pixsize, viewfac, sensor_size, dx, dy;
int sensor_fit;
- /* fields rendering */
params->ycor = yasp / xasp;
- if (params->use_fields)
- params->ycor *= 2.0f;
if (params->is_ortho) {
/* orthographic camera */
@@ -326,18 +315,6 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win
viewplane.xmax += dx;
viewplane.ymax += dy;
- /* fields offset */
- if (params->field_second) {
- if (params->field_odd) {
- viewplane.ymin -= 0.5f * params->ycor;
- viewplane.ymax -= 0.5f * params->ycor;
- }
- else {
- viewplane.ymin += 0.5f * params->ycor;
- viewplane.ymax += 0.5f * params->ycor;
- }
- }
-
/* the window matrix is used for clipping, and not changed during OSA steps */
/* using an offset of +0.5 here would give clip errors on edges */
viewplane.xmin *= pixsize;
@@ -641,7 +618,7 @@ static bool camera_frame_fit_calc_from_data(
/* don't move the camera, just yield the fit location */
/* r_scale only valid/useful for ortho cameras */
bool BKE_camera_view_frame_fit_to_scene(
- Main *bmain, Scene *scene, struct View3D *v3d, Object *camera_ob, float r_co[3], float *r_scale)
+ Depsgraph *depsgraph, Scene *scene, Object *camera_ob, float r_co[3], float *r_scale)
{
CameraParams params;
CameraViewFrameData data_cb;
@@ -652,22 +629,24 @@ bool BKE_camera_view_frame_fit_to_scene(
camera_frame_fit_data_init(scene, camera_ob, &params, &data_cb);
/* run callback on all visible points */
- BKE_scene_foreach_display_point(bmain, scene, v3d, BA_SELECT, camera_to_frame_view_cb, &data_cb);
+ BKE_scene_foreach_display_point(depsgraph, camera_to_frame_view_cb, &data_cb);
return camera_frame_fit_calc_from_data(&params, &data_cb, r_co, r_scale);
}
bool BKE_camera_view_frame_fit_to_coords(
- const Scene *scene, const float (*cos)[3], int num_cos, const Object *camera_ob,
+ const Depsgraph *depsgraph, const float (*cos)[3], int num_cos, Object *camera_ob,
float r_co[3], float *r_scale)
{
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *camera_ob_eval = DEG_get_evaluated_object(depsgraph, camera_ob);
CameraParams params;
CameraViewFrameData data_cb;
/* just in case */
*r_scale = 1.0f;
- camera_frame_fit_data_init(scene, camera_ob, &params, &data_cb);
+ camera_frame_fit_data_init(scene_eval, camera_ob_eval, &params, &data_cb);
/* run callback on all given coordinates */
while (num_cos--) {
@@ -679,12 +658,12 @@ bool BKE_camera_view_frame_fit_to_coords(
/******************* multiview matrix functions ***********************/
-static void camera_model_matrix(Object *camera, float r_modelmat[4][4])
+static void camera_model_matrix(const Object *camera, float r_modelmat[4][4])
{
copy_m4_m4(r_modelmat, camera->obmat);
}
-static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, float r_modelmat[4][4])
+static void camera_stereo3d_model_matrix(const Object *camera, const bool is_left, float r_modelmat[4][4])
{
Camera *data = (Camera *)camera->data;
float interocular_distance, convergence_distance;
@@ -782,7 +761,7 @@ static void camera_stereo3d_model_matrix(Object *camera, const bool is_left, flo
}
/* the view matrix is used by the viewport drawing, it is basically the inverted model matrix */
-void BKE_camera_multiview_view_matrix(RenderData *rd, Object *camera, const bool is_left, float r_viewmat[4][4])
+void BKE_camera_multiview_view_matrix(RenderData *rd, const Object *camera, const bool is_left, float r_viewmat[4][4])
{
BKE_camera_multiview_model_matrix(rd, camera, is_left ? STEREO_LEFT_NAME : STEREO_RIGHT_NAME, r_viewmat);
invert_m4(r_viewmat);
@@ -797,7 +776,7 @@ static bool camera_is_left(const char *viewname)
return true;
}
-void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const char *viewname, float r_modelmat[4][4])
+void BKE_camera_multiview_model_matrix(RenderData *rd, const Object *camera, const char *viewname, float r_modelmat[4][4])
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
@@ -814,7 +793,7 @@ void BKE_camera_multiview_model_matrix(RenderData *rd, Object *camera, const cha
normalize_m4(r_modelmat);
}
-bool BKE_camera_multiview_spherical_stereo(RenderData *rd, Object *camera)
+bool BKE_camera_multiview_spherical_stereo(RenderData *rd, const Object *camera)
{
Camera *cam;
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
@@ -861,9 +840,9 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha
}
if (name[0] != '\0') {
- Base *base = BKE_scene_base_find_by_name(scene, name);
- if (base) {
- return base->object;
+ Object *ob = BKE_scene_object_find_by_name(scene, name);
+ if (ob != NULL) {
+ return ob;
}
}
@@ -887,7 +866,7 @@ Object *BKE_camera_multiview_render(Scene *scene, Object *camera, const char *vi
}
}
-static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
+static float camera_stereo3d_shift_x(const Object *camera, const char *viewname)
{
Camera *data = camera->data;
float shift = data->shiftx;
@@ -925,7 +904,7 @@ static float camera_stereo3d_shift_x(Object *camera, const char *viewname)
return shift;
}
-float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *viewname)
+float BKE_camera_multiview_shift_x(RenderData *rd, const Object *camera, const char *viewname)
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
Camera *data = camera->data;
@@ -943,7 +922,7 @@ float BKE_camera_multiview_shift_x(RenderData *rd, Object *camera, const char *v
}
}
-void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, Object *camera, const char *viewname)
+void BKE_camera_multiview_params(RenderData *rd, CameraParams *params, const Object *camera, const char *viewname)
{
if (camera->type == OB_CAMERA) {
params->shiftx = BKE_camera_multiview_shift_x(rd, camera, viewname);
@@ -960,3 +939,38 @@ void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_set
r_fx_settings->dof->focus_distance = BKE_camera_object_dof_distance(camera);
}
}
+
+CameraBGImage *BKE_camera_background_image_new(Camera *cam)
+{
+ CameraBGImage *bgpic = MEM_callocN(sizeof(CameraBGImage), "Background Image");
+
+ bgpic->scale = 1.0f;
+ bgpic->alpha = 0.5f;
+ bgpic->iuser.ok = 1;
+ bgpic->iuser.flag |= IMA_ANIM_ALWAYS;
+ bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED;
+
+ BLI_addtail(&cam->bg_images, bgpic);
+
+ return bgpic;
+}
+
+void BKE_camera_background_image_remove(Camera *cam, CameraBGImage *bgpic)
+{
+ BLI_remlink(&cam->bg_images, bgpic);
+
+ MEM_freeN(bgpic);
+}
+
+void BKE_camera_background_image_clear(Camera *cam)
+{
+ CameraBGImage *bgpic = cam->bg_images.first;
+
+ while (bgpic) {
+ CameraBGImage *next_bgpic = bgpic->next;
+
+ BKE_camera_background_image_remove(cam, bgpic);
+
+ bgpic = next_bgpic;
+ }
+}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index ed2b8cddc14..1c3b75b1771 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -46,6 +46,7 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_editmesh.h"
#include "BKE_curve.h"
@@ -57,12 +58,6 @@
#include "MEM_guardedalloc.h"
-#include "GPU_buffers.h"
-#include "GPU_draw.h"
-#include "GPU_glew.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
#include <string.h>
#include <limits.h>
#include <math.h>
@@ -104,7 +99,7 @@ static int cdDM_getNumTessFaces(DerivedMesh *dm)
* to help debug tessfaces issues since BMESH merge. */
#if 0
if (dm->numTessFaceData == 0 && dm->numPolyData != 0) {
- printf("%s: has no faces!, call DM_ensure_tessface() if you need them\n");
+ printf("%s: has no faces!\n");
}
#endif
return dm->numTessFaceData;
@@ -295,7 +290,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
* this derivedmesh is just original mesh. it's the multires subsurf dm
* that this is actually for, to support a pbvh on a modified mesh */
if (!cddm->pbvh && ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
MLoopTri *looptri;
bool deformed;
@@ -330,7 +325,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
totvert = deformdm->getNumVerts(deformdm);
vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "cdDM_getPBVH vertCos");
deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos, totvert);
MEM_freeN(vertCos);
}
}
@@ -338,1450 +333,6 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
return cddm->pbvh;
}
-/* update vertex normals so that drawing smooth faces works during sculpt
- * TODO: proper fix is to support the pbvh in all drawing modes */
-static void cdDM_update_normals_from_pbvh(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- float (*face_nors)[3];
-
- /* Some callbacks do not use optimal PBVH draw, so needs all the
- * possible data (like normals) to be copied from PBVH back to DM.
- *
- * This is safe to do if PBVH and DM are representing the same mesh,
- * which could be wrong when modifiers are enabled for sculpt.
- * So here we only doing update when there's no modifiers applied
- * during sculpt.
- *
- * It's safe to do nothing if there are modifiers, because in this
- * case modifier stack is re-constructed from scratch on every
- * update.
- */
- if (!cddm->pbvh_draw) {
- return;
- }
-
- face_nors = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
- BKE_pbvh_update(cddm->pbvh, PBVH_UpdateNormals, face_nors);
-}
-
-static void cdDM_drawVerts(DerivedMesh *dm)
-{
- GPU_vertex_setup(dm);
- if (dm->drawObject->tot_loop_verts)
- glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loop_verts);
- else
- glDrawArrays(GL_POINTS, 0, dm->drawObject->tot_loose_point);
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawUVEdges(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- int totpoly = dm->getNumPolys(dm);
- int prevstart = 0;
- bool prevdraw = true;
- int curpos = 0;
- int i;
-
- GPU_uvedge_setup(dm);
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool draw = (mpoly->flag & ME_HIDE) == 0;
-
- if (prevdraw != draw) {
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- prevstart = curpos;
- }
-
- curpos += 2 * mpoly->totloop;
- prevdraw = draw;
- }
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- GPUDrawObject *gdo;
- if (cddm->pbvh && cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH)
- {
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, true, false);
-
- return;
- }
-
- GPU_edge_setup(dm);
- gdo = dm->drawObject;
- if (gdo->edges && gdo->points) {
- if (drawAllEdges && drawLooseEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->totedge * 2);
- }
- else if (drawAllEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2);
- }
- else {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2);
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, dm->drawObject->tot_loose_edge_drawn * 2);
- }
- }
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawLooseEdges(DerivedMesh *dm)
-{
- int start;
- int count;
-
- GPU_edge_setup(dm);
-
- start = (dm->drawObject->loose_edge_offset * 2);
- count = (dm->drawObject->totedge - dm->drawObject->loose_edge_offset) * 2;
-
- if (count) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count);
- }
-
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawFacesSolid(
- DerivedMesh *dm,
- float (*partial_redraw_planes)[4],
- bool UNUSED(fast), DMSetMaterial setMaterial)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- int a;
-
- if (cddm->pbvh) {
- if (cddm->pbvh_draw && BKE_pbvh_has_faces(cddm->pbvh)) {
- float (*face_nors)[3] = CustomData_get_layer(&dm->polyData, CD_NORMAL);
-
- BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors,
- setMaterial, false, false);
- return;
- }
- }
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- for (a = 0; a < dm->drawObject->totmaterial; a++) {
- if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
- GPU_buffer_draw_elements(
- dm->drawObject->triangles, GL_TRIANGLES,
- dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
- }
- }
- GPU_buffers_unbind();
-}
-
-static void cdDM_drawFacesTex_common(
- DerivedMesh *dm,
- DMSetDrawOptionsTex drawParams,
- DMSetDrawOptionsMappedTex drawParamsMapped,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- const MLoopCol *mloopcol = NULL;
- int i;
- int colType, start_element, tot_drawn;
- const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
- const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
- const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
- int totpoly;
- int next_actualFace;
- int mat_index;
- int tot_element;
-
- /* double lookup */
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- /* TODO: not entirely correct, but currently dynamic topology will
- * destroy UVs anyway, so textured display wouldn't work anyway
- *
- * this will do more like solid view with lights set up for
- * textured view, but object itself will be displayed gray
- * (the same as it'll display without UV maps in textured view)
- */
- if (cddm->pbvh) {
- if (cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
- BKE_pbvh_has_faces(cddm->pbvh))
- {
- GPU_set_tpage(NULL, false, false);
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
- return;
- }
- else {
- cdDM_update_normals_from_pbvh(dm);
- }
- }
-
- if (use_colors) {
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- }
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- if (flag & DM_DRAW_USE_TEXPAINT_UV)
- GPU_texpaint_uv_setup(dm);
- else
- GPU_uv_setup(dm);
- if (mloopcol) {
- GPU_color_setup(dm, colType);
- }
-
- /* lastFlag = 0; */ /* UNUSED */
- for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
- GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
- next_actualFace = bufmat->polys[0];
- totpoly = bufmat->totpolys;
-
- tot_element = 0;
- tot_drawn = 0;
- start_element = 0;
-
- for (i = 0; i < totpoly; i++) {
- int actualFace = bufmat->polys[i];
- DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
- int flush = 0;
- int tot_tri_verts;
-
- if (i != totpoly - 1)
- next_actualFace = bufmat->polys[i + 1];
-
- if (use_hide && (mpoly[actualFace].flag & ME_HIDE)) {
- draw_option = DM_DRAW_OPTION_SKIP;
- }
- else if (drawParams) {
- MTexPoly *tp = use_tface && mtexpoly ? &mtexpoly[actualFace] : NULL;
- draw_option = drawParams(tp, (mloopcol != NULL), mpoly[actualFace].mat_nr);
- }
- else {
- if (index_mp_to_orig) {
- const int orig = index_mp_to_orig[actualFace];
- if (orig == ORIGINDEX_NONE) {
- /* XXX, this is not really correct
- * it will draw the previous faces context for this one when we don't know its settings.
- * but better then skipping it altogether. - campbell */
- draw_option = DM_DRAW_OPTION_NORMAL;
- }
- else if (drawParamsMapped) {
- draw_option = drawParamsMapped(userData, orig, mpoly[actualFace].mat_nr);
- }
- }
- else if (drawParamsMapped) {
- draw_option = drawParamsMapped(userData, actualFace, mpoly[actualFace].mat_nr);
- }
- }
-
- /* flush buffer if current triangle isn't drawable or it's last triangle */
- flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1);
-
- if (!flush && compareDrawOptions) {
- /* also compare draw options and flush buffer if they're different
- * need for face selection highlight in edit mode */
- flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
- }
-
- tot_tri_verts = ME_POLY_TRI_TOT(&mpoly[actualFace]) * 3;
- tot_element += tot_tri_verts;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP)
- tot_drawn += tot_tri_verts;
-
- if (tot_drawn) {
- if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL)
- GPU_color_switch(1);
- else
- GPU_color_switch(0);
-
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
- tot_drawn = 0;
- }
- start_element = tot_element;
- }
- else {
- tot_drawn += tot_tri_verts;
- }
- }
- }
-
- GPU_buffers_unbind();
-
-}
-
-static void cdDM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
-}
-
-static void cdDM_drawMappedFaces(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- const MPoly *mpoly = cddm->mpoly;
- const MLoopCol *mloopcol = NULL;
- const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
- const bool use_hide = (flag & DM_DRAW_SKIP_HIDDEN) != 0;
- int colType;
- int i, j;
- int start_element = 0, tot_element, tot_drawn;
- int totpoly;
- int tot_tri_elem;
- int mat_index;
- GPUBuffer *findex_buffer = NULL;
-
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- if (cddm->pbvh) {
- if (G.debug_value == 14)
- BKE_pbvh_draw_BB(cddm->pbvh);
- }
-
- /* fist, setup common buffers */
- GPU_vertex_setup(dm);
- GPU_triangle_setup(dm);
-
- totpoly = dm->getNumPolys(dm);
-
- /* if we do selection, fill the selection buffer color */
- if (G.f & G_BACKBUFSEL) {
- if (!(flag & DM_DRAW_SKIP_SELECT)) {
- Mesh *me = NULL;
- BMesh *bm = NULL;
- unsigned int *fi_map;
-
- if (flag & DM_DRAW_SELECT_USE_EDITMODE)
- bm = userData;
- else
- me = userData;
-
- findex_buffer = GPU_buffer_alloc(dm->drawObject->tot_loop_verts * sizeof(int));
- fi_map = GPU_buffer_lock(findex_buffer, GPU_BINDING_ARRAY);
-
- if (fi_map) {
- for (i = 0; i < totpoly; i++, mpoly++) {
- int selcol = 0xFFFFFFFF;
- const int orig = (index_mp_to_orig) ? index_mp_to_orig[i] : i;
- bool is_hidden;
-
- if (orig != ORIGINDEX_NONE) {
- if (use_hide) {
- if (flag & DM_DRAW_SELECT_USE_EDITMODE) {
- BMFace *efa = BM_face_at_index(bm, orig);
- is_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0;
- }
- else {
- is_hidden = (me->mpoly[orig].flag & ME_HIDE) != 0;
- }
-
- if (!is_hidden) {
- GPU_select_index_get(orig + 1, &selcol);
- }
- }
- else {
- GPU_select_index_get(orig + 1, &selcol);
- }
- }
-
- for (j = 0; j < mpoly->totloop; j++)
- fi_map[start_element++] = selcol;
- }
-
- start_element = 0;
- mpoly = cddm->mpoly;
-
- GPU_buffer_unlock(findex_buffer, GPU_BINDING_ARRAY);
- GPU_buffer_bind_as_color(findex_buffer);
- }
- }
- }
- else {
- GPU_normal_setup(dm);
-
- if (use_colors) {
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = DM_get_loop_data_layer(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = DM_get_loop_data_layer(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = DM_get_loop_data_layer(dm, colType);
- }
-
- if (use_colors && mloopcol) {
- GPU_color_setup(dm, colType);
- }
- }
- }
-
- tot_tri_elem = dm->drawObject->tot_triangle_point;
-
- if (tot_tri_elem == 0) {
- /* avoid buffer problems in following code */
- }
- else if (setDrawOptions == NULL) {
- /* just draw the entire face array */
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, 0, tot_tri_elem);
- }
- else {
- for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
- GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
- DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
- int next_actualFace = bufmat->polys[0];
- totpoly = use_hide ? bufmat->totvisiblepolys : bufmat->totpolys;
-
- tot_element = 0;
- start_element = 0;
- tot_drawn = 0;
-
- if (setMaterial)
- draw_option = setMaterial(bufmat->mat_nr + 1, NULL);
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- DMDrawOption last_draw_option = DM_DRAW_OPTION_NORMAL;
-
- for (i = 0; i < totpoly; i++) {
- int actualFace = next_actualFace;
- int flush = 0;
- int tot_tri_verts;
-
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (i != totpoly - 1)
- next_actualFace = bufmat->polys[i + 1];
-
- if (setDrawOptions) {
- const int orig = (index_mp_to_orig) ? index_mp_to_orig[actualFace] : actualFace;
-
- if (orig != ORIGINDEX_NONE) {
- draw_option = setDrawOptions(userData, orig);
- }
- }
-
- /* Goal is to draw as long of a contiguous triangle
- * array as possible, so draw when we hit either an
- * invisible triangle or at the end of the array */
-
- /* flush buffer if current triangle isn't drawable or it's last triangle... */
- flush = (draw_option != last_draw_option) || (i == totpoly - 1);
-
- if (!flush && compareDrawOptions) {
- flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
- }
-
- tot_tri_verts = ME_POLY_TRI_TOT(&mpoly[actualFace]) * 3;
- tot_element += tot_tri_verts;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- tot_drawn += tot_tri_verts;
-
- if (last_draw_option != draw_option) {
- if (draw_option == DM_DRAW_OPTION_STIPPLE) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- }
- }
-
- if (tot_drawn) {
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
- tot_drawn = 0;
- }
-
- last_draw_option = draw_option;
- start_element = tot_element;
- }
- else {
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- tot_drawn += tot_tri_verts;
- }
- else {
- start_element = tot_element;
- }
- }
- }
- }
- }
- }
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-
- GPU_buffers_unbind();
-
- if (findex_buffer)
- GPU_buffer_free(findex_buffer);
-
-}
-
-static void cdDM_drawMappedFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
-}
-
-static void cddm_draw_attrib_vertex(
- DMVertexAttribs *attribs, const MVert *mvert, int a, int index, int loop, int vert,
- const float *lnor, const bool smoothnormal)
-{
- DM_draw_attrib_vertex(attribs, a, index, vert, loop);
-
- /* vertex normal */
- if (lnor) {
- glNormal3fv(lnor);
- }
- else if (smoothnormal) {
- glNormal3sv(mvert[index].no);
- }
-
- /* vertex coordinate */
- glVertex3fv(mvert[index].co);
-}
-
-typedef struct {
- DMVertexAttribs attribs;
- int numdata;
-
- GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/
-} GPUMaterialConv;
-
-static void cdDM_drawMappedFacesGLSL(
- DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- GPUVertexAttribs gattribs;
- const MVert *mvert = cddm->mvert;
- const MPoly *mpoly = cddm->mpoly;
- const MLoop *mloop = cddm->mloop;
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
- const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- const int totpoly = dm->getNumPolys(dm);
- const short dm_totmat = dm->totmat;
- int a, b, matnr, new_matnr;
- bool do_draw;
- int orig;
-
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- /* TODO: same as for solid draw, not entirely correct, but works fine for now,
- * will skip using textures (dyntopo currently destroys UV anyway) and
- * works fine for matcap
- */
- if (cddm->pbvh) {
- if (cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
- BKE_pbvh_has_faces(cddm->pbvh))
- {
- setMaterial(1, &gattribs);
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
- return;
- }
- else {
- cdDM_update_normals_from_pbvh(dm);
- }
- }
-
- matnr = -1;
- do_draw = false;
-
- if (setDrawOptions != NULL) {
- DMVertexAttribs attribs;
- DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n");
- memset(&attribs, 0, sizeof(attribs));
-
- glBegin(GL_TRIANGLES);
-
- for (a = 0; a < tottri; a++, lt++) {
- const MPoly *mp = &mpoly[lt->poly];
- const unsigned int vtri[3] = {mloop[lt->tri[0]].v, mloop[lt->tri[1]].v, mloop[lt->tri[2]].v};
- const unsigned int *ltri = lt->tri;
- const float *ln1 = NULL, *ln2 = NULL, *ln3 = NULL;
- const bool smoothnormal = lnors || (mp->flag & ME_SMOOTH);
- new_matnr = mp->mat_nr;
-
- if (new_matnr != matnr) {
- glEnd();
-
- matnr = new_matnr;
- do_draw = setMaterial(matnr + 1, &gattribs);
- if (do_draw) {
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- DM_draw_attrib_vertex_uniforms(&attribs);
- }
-
- glBegin(GL_TRIANGLES);
- }
-
- if (!do_draw) {
- continue;
- }
- else /* if (setDrawOptions) */ {
- orig = (index_mp_to_orig) ? index_mp_to_orig[lt->poly] : lt->poly;
-
- if (orig == ORIGINDEX_NONE) {
- /* since the material is set by setMaterial(), faces with no
- * origin can be assumed to be generated by a modifier */
-
- /* continue */
- }
- else if (setDrawOptions(userData, orig) == DM_DRAW_OPTION_SKIP)
- continue;
- }
-
- if (!smoothnormal) {
- if (nors) {
- glNormal3fv(nors[lt->poly]);
- }
- else {
- /* TODO ideally a normal layer should always be available */
- float nor[3];
- normal_tri_v3(nor, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- glNormal3fv(nor);
- }
- }
- else if (lnors) {
- ln1 = lnors[ltri[0]];
- ln2 = lnors[ltri[1]];
- ln3 = lnors[ltri[2]];
- }
-
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[0], ltri[0], 0, ln1, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[1], ltri[1], 1, ln2, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal);
- }
- glEnd();
- }
- else {
- GPUMaterialConv *matconv;
- int offset;
- int *mat_orig_to_new;
- int tot_active_mat;
- GPUBuffer *buffer = NULL;
- unsigned char *varray;
- size_t max_element_size = 0;
- int tot_loops = 0;
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
-
- tot_active_mat = dm->drawObject->totmaterial;
-
- matconv = MEM_calloc_arrayN(tot_active_mat, sizeof(*matconv),
- "cdDM_drawMappedFacesGLSL.matconv");
- mat_orig_to_new = MEM_malloc_arrayN(dm->totmat, sizeof(*mat_orig_to_new),
- "cdDM_drawMappedFacesGLSL.mat_orig_to_new");
-
- /* part one, check what attributes are needed per material */
- for (a = 0; a < tot_active_mat; a++) {
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- /* map from original material index to new
- * GPUBufferMaterial index */
- mat_orig_to_new[new_matnr] = a;
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- int numdata = 0;
- DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs);
-
- if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
- matconv[a].datatypes[numdata].size = 3;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- for (b = 0; b < matconv[a].attribs.tottface; b++) {
- if (matconv[a].attribs.tface[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 2;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.totmcol; b++) {
- if (matconv[a].attribs.mcol[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.tottang; b++) {
- if (matconv[a].attribs.tang[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- if (numdata != 0) {
- matconv[a].numdata = numdata;
- max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size);
- }
- }
- }
-
- /* part two, generate and fill the arrays with the data */
- if (max_element_size > 0) {
- buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts);
-
- varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY);
- if (varray == NULL) {
- GPU_buffers_unbind();
- GPU_buffer_free(buffer);
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- fprintf(stderr, "Out of memory, can't draw object\n");
- return;
- }
-
- for (a = 0; a < totpoly; a++, mpoly++) {
- const short mat_nr = ME_MAT_NR_TEST(mpoly->mat_nr, dm_totmat);
- int j;
- int i = mat_orig_to_new[mat_nr];
- offset = tot_loops * max_element_size;
-
- if (matconv[i].numdata != 0) {
- if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) {
- for (j = 0; j < mpoly->totloop; j++)
- copy_v3_v3((float *)&varray[offset + j * max_element_size],
- (float *)matconv[i].attribs.orco.array[mloop[mpoly->loopstart + j].v]);
- offset += sizeof(float) * 3;
- }
- for (b = 0; b < matconv[i].attribs.tottface; b++) {
- if (matconv[i].attribs.tface[b].array) {
- const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v2_v2((float *)&varray[offset + j * max_element_size], mloopuv[mpoly->loopstart + j].uv);
- offset += sizeof(float) * 2;
- }
- }
- for (b = 0; b < matconv[i].attribs.totmcol; b++) {
- if (matconv[i].attribs.mcol[b].array) {
- const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v4_v4_uchar(&varray[offset + j * max_element_size], &mloopcol[mpoly->loopstart + j].r);
- offset += sizeof(unsigned char) * 4;
- }
- }
- for (b = 0; b < matconv[i].attribs.tottang; b++) {
- if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
- const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array;
- for (j = 0; j < mpoly->totloop; j++)
- copy_v4_v4((float *)&varray[offset + j * max_element_size], looptang[mpoly->loopstart + j]);
- offset += sizeof(float) * 4;
- }
- }
- }
-
- tot_loops += mpoly->totloop;
- }
- GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY);
- }
-
- for (a = 0; a < tot_active_mat; a++) {
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size);
- }
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES,
- dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_unbind();
- }
- }
- }
-
- GPU_buffers_unbind();
- if (buffer)
- GPU_buffer_free(buffer);
-
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- }
-}
-
-static void cdDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-static void cdDM_drawMappedFacesMat(
- DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- GPUVertexAttribs gattribs;
- DMVertexAttribs attribs;
- MVert *mvert = cddm->mvert;
- const MPoly *mpoly = cddm->mpoly;
- const MLoop *mloop = cddm->mloop;
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
- const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int a, matnr, new_matnr;
- int orig;
-
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
-
- /* TODO: same as for solid draw, not entirely correct, but works fine for now,
- * will skip using textures (dyntopo currently destroys UV anyway) and
- * works fine for matcap
- */
-
- if (cddm->pbvh) {
- if (cddm->pbvh_draw &&
- BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH &&
- BKE_pbvh_has_faces(cddm->pbvh))
- {
- setMaterial(userData, 1, &gattribs);
- BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, false, false);
- return;
- }
- else {
- cdDM_update_normals_from_pbvh(dm);
- }
- }
-
- matnr = -1;
-
- memset(&attribs, 0, sizeof(attribs));
-
- glBegin(GL_TRIANGLES);
-
- for (a = 0; a < tottri; a++, lt++) {
- const MPoly *mp = &mpoly[lt->poly];
- const unsigned int vtri[3] = {mloop[lt->tri[0]].v, mloop[lt->tri[1]].v, mloop[lt->tri[2]].v};
- const unsigned int *ltri = lt->tri;
- const bool smoothnormal = lnors || (mp->flag & ME_SMOOTH);
- const float *ln1 = NULL, *ln2 = NULL, *ln3 = NULL;
-
- /* material */
- new_matnr = mp->mat_nr + 1;
-
- if (new_matnr != matnr) {
- glEnd();
-
- setMaterial(userData, matnr = new_matnr, &gattribs);
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- DM_draw_attrib_vertex_uniforms(&attribs);
-
- glBegin(GL_TRIANGLES);
- }
-
- /* skipping faces */
- if (setFace) {
- orig = (index_mp_to_orig) ? index_mp_to_orig[lt->poly] : lt->poly;
-
- if (orig != ORIGINDEX_NONE && !setFace(userData, orig))
- continue;
- }
-
- /* smooth normal */
- if (!smoothnormal) {
- if (nors) {
- glNormal3fv(nors[lt->poly]);
- }
- else {
- /* TODO ideally a normal layer should always be available */
- float nor[3];
- normal_tri_v3(nor, mvert[vtri[0]].co, mvert[vtri[1]].co, mvert[vtri[2]].co);
- glNormal3fv(nor);
- }
- }
- else if (lnors) {
- ln1 = lnors[ltri[0]];
- ln2 = lnors[ltri[1]];
- ln3 = lnors[ltri[2]];
- }
-
- /* vertices */
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[0], ltri[0], 0, ln1, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[1], ltri[1], 1, ln2, smoothnormal);
- cddm_draw_attrib_vertex(&attribs, mvert, a, vtri[2], ltri[2], 2, ln3, smoothnormal);
- }
- glEnd();
-}
-
-static void cdDM_drawMappedEdges(DerivedMesh *dm, DMSetDrawOptions setDrawOptions, void *userData)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
- MVert *vert = cddm->mvert;
- MEdge *edge = cddm->medge;
- int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
-
- glBegin(GL_LINES);
- for (i = 0; i < dm->numEdgeData; i++, edge++) {
- if (index) {
- orig = *index++;
- if (setDrawOptions && orig == ORIGINDEX_NONE) continue;
- }
- else
- orig = i;
-
- if (!setDrawOptions || (setDrawOptions(userData, orig) != DM_DRAW_OPTION_SKIP)) {
- glVertex3fv(vert[edge->v1].co);
- glVertex3fv(vert[edge->v2].co);
- }
- }
- glEnd();
-}
-
-typedef struct FaceCount {
- unsigned int i_visible;
- unsigned int i_hidden;
- unsigned int i_tri_visible;
- unsigned int i_tri_hidden;
-} FaceCount;
-
-static void cdDM_buffer_copy_triangles(
- DerivedMesh *dm, unsigned int *varray,
- const int *mat_orig_to_new)
-{
- GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials;
- int i, j, start;
-
- const int gpu_totmat = dm->drawObject->totmaterial;
- const short dm_totmat = dm->totmat;
- const MPoly *mpoly = dm->getPolyArray(dm);
- const MLoopTri *lt = dm->getLoopTriArray(dm);
- const int totpoly = dm->getNumPolys(dm);
-
- FaceCount *fc = MEM_malloc_arrayN(gpu_totmat, sizeof(*fc), "gpumaterial.facecount");
-
- for (i = 0; i < gpu_totmat; i++) {
- fc[i].i_visible = 0;
- fc[i].i_tri_visible = 0;
- fc[i].i_hidden = gpumaterials[i].totpolys - 1;
- fc[i].i_tri_hidden = gpumaterials[i].totelements - 1;
- }
-
- for (i = 0; i < totpoly; i++) {
- const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat);
- int tottri = ME_POLY_TRI_TOT(&mpoly[i]);
- int mati = mat_orig_to_new[mat_nr];
- gpumat = gpumaterials + mati;
-
- if (mpoly[i].flag & ME_HIDE) {
- for (j = 0; j < tottri; j++, lt++) {
- start = gpumat->start + fc[mati].i_tri_hidden;
- /* v1 v2 v3 */
- varray[start--] = lt->tri[2];
- varray[start--] = lt->tri[1];
- varray[start--] = lt->tri[0];
- fc[mati].i_tri_hidden -= 3;
- }
- gpumat->polys[fc[mati].i_hidden--] = i;
- }
- else {
- for (j = 0; j < tottri; j++, lt++) {
- start = gpumat->start + fc[mati].i_tri_visible;
- /* v1 v2 v3 */
- varray[start++] = lt->tri[0];
- varray[start++] = lt->tri[1];
- varray[start++] = lt->tri[2];
- fc[mati].i_tri_visible += 3;
- }
- gpumat->polys[fc[mati].i_visible++] = i;
- }
- }
-
- /* set the visible polygons */
- for (i = 0; i < gpu_totmat; i++) {
- gpumaterials[i].totvisiblepolys = fc[i].i_visible;
- }
-
- MEM_freeN(fc);
-}
-
-static void cdDM_buffer_copy_vertex(
- DerivedMesh *dm, float *varray)
-{
- const MVert *mvert;
- const MPoly *mpoly;
- const MLoop *mloop;
-
- int i, j, start, totpoly;
-
- mvert = dm->getVertArray(dm);
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
- totpoly = dm->getNumPolys(dm);
-
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v3_v3(&varray[start], mvert[mloop[mpoly->loopstart + j].v].co);
- start += 3;
- }
- }
-
- /* copy loose points */
- j = dm->drawObject->tot_loop_verts * 3;
- for (i = 0; i < dm->drawObject->totvert; i++) {
- if (dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_loop_verts) {
- copy_v3_v3(&varray[j], mvert[i].co);
- j += 3;
- }
- }
-}
-
-static void cdDM_buffer_copy_normal(
- DerivedMesh *dm, short *varray)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- int i, j, totpoly;
- int start;
-
- const float (*nors)[3] = dm->getPolyDataArray(dm, CD_NORMAL);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-
- const MVert *mvert;
- const MPoly *mpoly;
- const MLoop *mloop;
-
- mvert = dm->getVertArray(dm);
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
- totpoly = dm->getNumPolys(dm);
-
- /* we are in sculpt mode, disable loop normals (since they won't get updated) */
- if (cddm->pbvh)
- lnors = NULL;
-
- start = 0;
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool smoothnormal = (mpoly->flag & ME_SMOOTH) != 0;
-
- if (lnors) {
- /* Copy loop normals */
- for (j = 0; j < mpoly->totloop; j++, start += 4) {
- normal_float_to_short_v3(&varray[start], lnors[mpoly->loopstart + j]);
- }
- }
- else if (smoothnormal) {
- /* Copy vertex normal */
- for (j = 0; j < mpoly->totloop; j++, start += 4) {
- copy_v3_v3_short(&varray[start], mvert[mloop[mpoly->loopstart + j].v].no);
- }
- }
- else {
- /* Copy cached OR calculated face normal */
- short f_no_s[3];
-
- if (nors) {
- normal_float_to_short_v3(f_no_s, nors[i]);
- }
- else {
- float f_no[3];
- BKE_mesh_calc_poly_normal(mpoly, &mloop[mpoly->loopstart], mvert, f_no);
- normal_float_to_short_v3(f_no_s, f_no);
- }
-
- for (j = 0; j < mpoly->totloop; j++, start += 4) {
- copy_v3_v3_short(&varray[start], f_no_s);
- }
- }
- }
-}
-
-static void cdDM_buffer_copy_uv(
- DerivedMesh *dm, float *varray)
-{
- int i, j, totpoly;
- int start;
-
- const MPoly *mpoly;
- const MLoopUV *mloopuv;
-
- if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
- return;
- }
-
- mpoly = dm->getPolyArray(dm);
- totpoly = dm->getNumPolys(dm);
-
- start = 0;
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
- start += 2;
- }
- }
-}
-
-static void cdDM_buffer_copy_uv_texpaint(
- DerivedMesh *dm, float *varray)
-{
- int i, j, totpoly;
- int start;
-
- const MPoly *mpoly;
-
- int totmaterial = dm->totmat;
- const MLoopUV **uv_base;
- const MLoopUV *uv_stencil_base;
- int stencil;
-
- totpoly = dm->getNumPolys(dm);
-
- /* should have been checked for before, reassert */
- BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV));
- uv_base = MEM_malloc_arrayN(totmaterial, sizeof(*uv_base), "texslots");
-
- for (i = 0; i < totmaterial; i++) {
- uv_base[i] = DM_paint_uvlayer_active_get(dm, i);
- }
-
- stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV);
- uv_stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil);
-
- mpoly = dm->getPolyArray(dm);
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- int mat_i = mpoly->mat_nr;
-
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], uv_base[mat_i][mpoly->loopstart + j].uv);
- copy_v2_v2(&varray[start + 2], uv_stencil_base[mpoly->loopstart + j].uv);
- start += 4;
- }
- }
-
- MEM_freeN((void *)uv_base);
-}
-
-/* treat varray_ as an array of MCol, four MCol's per face */
-static void cdDM_buffer_copy_mcol(
- DerivedMesh *dm, unsigned char *varray,
- const void *user_data)
-{
- int i, j, totpoly;
- int start;
-
- const MLoopCol *mloopcol = user_data;
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- totpoly = dm->getNumPolys(dm);
-
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v4_v4_uchar(&varray[start], &mloopcol[mpoly->loopstart + j].r);
- start += 4;
- }
- }
-}
-
-static void cdDM_buffer_copy_edge(
- DerivedMesh *dm, unsigned int *varray)
-{
- MEdge *medge, *medge_base;
- int i, totedge, iloose, inorm, iloosehidden, inormhidden;
- int tot_loose_hidden = 0, tot_loose = 0;
- int tot_hidden = 0, tot = 0;
-
- medge_base = medge = dm->getEdgeArray(dm);
- totedge = dm->getNumEdges(dm);
-
- for (i = 0; i < totedge; i++, medge++) {
- if (medge->flag & ME_EDGEDRAW) {
- if (medge->flag & ME_LOOSEEDGE) tot_loose++;
- else tot++;
- }
- else {
- if (medge->flag & ME_LOOSEEDGE) tot_loose_hidden++;
- else tot_hidden++;
- }
- }
-
- inorm = 0;
- inormhidden = tot;
- iloose = tot + tot_hidden;
- iloosehidden = iloose + tot_loose;
-
- medge = medge_base;
- for (i = 0; i < totedge; i++, medge++) {
- if (medge->flag & ME_EDGEDRAW) {
- if (medge->flag & ME_LOOSEEDGE) {
- varray[iloose * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[iloose * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- iloose++;
- }
- else {
- varray[inorm * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[inorm * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- inorm++;
- }
- }
- else {
- if (medge->flag & ME_LOOSEEDGE) {
- varray[iloosehidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[iloosehidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- iloosehidden++;
- }
- else {
- varray[inormhidden * 2] = dm->drawObject->vert_points[medge->v1].point_index;
- varray[inormhidden * 2 + 1] = dm->drawObject->vert_points[medge->v2].point_index;
- inormhidden++;
- }
- }
- }
-
- dm->drawObject->tot_loose_edge_drawn = tot_loose;
- dm->drawObject->loose_edge_offset = tot + tot_hidden;
- dm->drawObject->tot_edge_drawn = tot;
-}
-
-static void cdDM_buffer_copy_uvedge(
- DerivedMesh *dm, float *varray)
-{
- int i, j, totpoly;
- int start;
- const MLoopUV *mloopuv;
- const MPoly *mpoly = dm->getPolyArray(dm);
-
- if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
- return;
- }
-
- totpoly = dm->getNumPolys(dm);
- start = 0;
-
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv);
- start += 4;
- }
- }
-}
-
-static void cdDM_copy_gpu_data(
- DerivedMesh *dm, int type, void *varray_p,
- const int *mat_orig_to_new, const void *user_data)
-{
- /* 'varray_p' cast is redundant but include for self-documentation */
- switch (type) {
- case GPU_BUFFER_VERTEX:
- cdDM_buffer_copy_vertex(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_NORMAL:
- cdDM_buffer_copy_normal(dm, (short *)varray_p);
- break;
- case GPU_BUFFER_COLOR:
- cdDM_buffer_copy_mcol(dm, (unsigned char *)varray_p, user_data);
- break;
- case GPU_BUFFER_UV:
- cdDM_buffer_copy_uv(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_UV_TEXPAINT:
- cdDM_buffer_copy_uv_texpaint(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_EDGE:
- cdDM_buffer_copy_edge(dm, (unsigned int *)varray_p);
- break;
- case GPU_BUFFER_UVEDGE:
- cdDM_buffer_copy_uvedge(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_TRIANGLES:
- cdDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new);
- break;
- default:
- break;
- }
-}
-
-/* add a new point to the list of points related to a particular
- * vertex */
-#ifdef USE_GPU_POINT_LINK
-
-static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
-{
- GPUVertPointLink *lnk;
-
- lnk = &gdo->vert_points[vert_index];
-
- /* if first link is in use, add a new link at the end */
- if (lnk->point_index != -1) {
- /* get last link */
- for (; lnk->next; lnk = lnk->next) ;
-
- /* add a new link from the pool */
- lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage];
- gdo->vert_points_usage++;
- }
-
- lnk->point_index = point_index;
-}
-
-#else
-
-static void cdDM_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
-{
- GPUVertPointLink *lnk;
- lnk = &gdo->vert_points[vert_index];
- if (lnk->point_index == -1) {
- lnk->point_index = point_index;
- }
-}
-
-#endif /* USE_GPU_POINT_LINK */
-
-/* for each vertex, build a list of points related to it; these lists
- * are stored in an array sized to the number of vertices */
-static void cdDM_drawobject_init_vert_points(
- GPUDrawObject *gdo,
- const MPoly *mpoly, const MLoop *mloop,
- int tot_poly)
-{
- int i;
- int tot_loops = 0;
-
- /* allocate the array and space for links */
- gdo->vert_points = MEM_malloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink),
- "GPUDrawObject.vert_points");
-#ifdef USE_GPU_POINT_LINK
- gdo->vert_points_mem = MEM_calloc_arrayN(gdo->totvert, sizeof(GPUVertPointLink),
- "GPUDrawObject.vert_points_mem");
- gdo->vert_points_usage = 0;
-#endif
-
- /* -1 indicates the link is not yet used */
- for (i = 0; i < gdo->totvert; i++) {
-#ifdef USE_GPU_POINT_LINK
- gdo->vert_points[i].link = NULL;
-#endif
- gdo->vert_points[i].point_index = -1;
- }
-
- for (i = 0; i < tot_poly; i++) {
- int j;
- const MPoly *mp = &mpoly[i];
-
- /* assign unique indices to vertices of the mesh */
- for (j = 0; j < mp->totloop; j++) {
- cdDM_drawobject_add_vert_point(gdo, mloop[mp->loopstart + j].v, tot_loops + j);
- }
- tot_loops += mp->totloop;
- }
-
- /* map any unused vertices to loose points */
- for (i = 0; i < gdo->totvert; i++) {
- if (gdo->vert_points[i].point_index == -1) {
- gdo->vert_points[i].point_index = gdo->tot_loop_verts + gdo->tot_loose_point;
- gdo->tot_loose_point++;
- }
- }
-}
-
-/* see GPUDrawObject's structure definition for a description of the
- * data being initialized here */
-static GPUDrawObject *cdDM_GPUobject_new(DerivedMesh *dm)
-{
- GPUDrawObject *gdo;
- const MPoly *mpoly;
- const MLoop *mloop;
- const short dm_totmat = dm->totmat;
- GPUBufferMaterial *mat_info;
- int i, totloops, totpolys;
-
- /* object contains at least one material (default included) so zero means uninitialized dm */
- BLI_assert(dm_totmat != 0);
-
- mpoly = dm->getPolyArray(dm);
- mloop = dm->getLoopArray(dm);
-
- totpolys = dm->getNumPolys(dm);
- totloops = dm->getNumLoops(dm);
-
- /* get the number of points used by each material, treating
- * each quad as two triangles */
- mat_info = MEM_calloc_arrayN(dm_totmat, sizeof(*mat_info), "GPU_drawobject_new.mat_orig_to_new");
-
- for (i = 0; i < totpolys; i++) {
- const short mat_nr = ME_MAT_NR_TEST(mpoly[i].mat_nr, dm_totmat);
- mat_info[mat_nr].totpolys++;
- mat_info[mat_nr].totelements += 3 * ME_POLY_TRI_TOT(&mpoly[i]);
- mat_info[mat_nr].totloops += mpoly[i].totloop;
- }
- /* create the GPUDrawObject */
- gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
- gdo->totvert = dm->getNumVerts(dm);
- gdo->totedge = dm->getNumEdges(dm);
-
- GPU_buffer_material_finalize(gdo, mat_info, dm_totmat);
-
- gdo->tot_loop_verts = totloops;
-
- /* store total number of points used for triangles */
- gdo->tot_triangle_point = poly_to_tri_count(totpolys, totloops) * 3;
-
- cdDM_drawobject_init_vert_points(gdo, mpoly, mloop, totpolys);
-
- return gdo;
-}
-
static void cdDM_foreachMappedVert(
DerivedMesh *dm,
void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
@@ -1913,7 +464,7 @@ void CDDM_recalc_tessellation_ex(DerivedMesh *dm, const bool do_face_nor_cpy)
/* Tessellation recreated faceData, and the active layer indices need to get re-propagated
* from loops and polys to faces */
- CustomData_bmesh_update_active_layers(&dm->faceData, &dm->polyData, &dm->loopData);
+ CustomData_bmesh_update_active_layers(&dm->faceData, &dm->loopData);
}
void CDDM_recalc_tessellation(DerivedMesh *dm)
@@ -2005,24 +556,6 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getPBVH = cdDM_getPBVH;
dm->getPolyMap = cdDM_getPolyMap;
- dm->drawVerts = cdDM_drawVerts;
-
- dm->drawUVEdges = cdDM_drawUVEdges;
- dm->drawEdges = cdDM_drawEdges;
- dm->drawLooseEdges = cdDM_drawLooseEdges;
- dm->drawMappedEdges = cdDM_drawMappedEdges;
-
- dm->drawFacesSolid = cdDM_drawFacesSolid;
- dm->drawFacesTex = cdDM_drawFacesTex;
- dm->drawFacesGLSL = cdDM_drawFacesGLSL;
- dm->drawMappedFaces = cdDM_drawMappedFaces;
- dm->drawMappedFacesTex = cdDM_drawMappedFacesTex;
- dm->drawMappedFacesGLSL = cdDM_drawMappedFacesGLSL;
- dm->drawMappedFacesMat = cdDM_drawMappedFacesMat;
-
- dm->gpuObjectNew = cdDM_GPUobject_new;
- dm->copy_gpu_data = cdDM_copy_gpu_data;
-
dm->foreachMappedVert = cdDM_foreachMappedVert;
dm->foreachMappedEdge = cdDM_foreachMappedEdge;
dm->foreachMappedLoop = cdDM_foreachMappedLoop;
@@ -2062,20 +595,31 @@ DerivedMesh *CDDM_new(int numVerts, int numEdges, int numTessFaces, int numLoops
DerivedMesh *CDDM_from_mesh(Mesh *mesh)
{
+ return CDDM_from_mesh_ex(mesh, CD_REFERENCE, CD_MASK_MESH);
+}
+
+DerivedMesh *CDDM_from_mesh_ex(Mesh *mesh, eCDAllocType alloctype, CustomDataMask mask)
+{
CDDerivedMesh *cddm = cdDM_create(__func__);
DerivedMesh *dm = &cddm->dm;
- CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS);
- int alloctype;
+
+ mask &= ~CD_MASK_MDISPS;
/* this does a referenced copy, with an exception for fluidsim */
DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, 0 /* mesh->totface */,
mesh->totloop, mesh->totpoly);
+ /* This should actually be dm->deformedOnly = mesh->runtime.deformed_only,
+ * but only if the original mesh had its deformed_only flag correctly set
+ * (which isn't generally the case). */
dm->deformedOnly = 1;
dm->cd_flag = mesh->cd_flag;
- alloctype = CD_REFERENCE;
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ dm->dirty |= DM_DIRTY_NORMALS;
+ }
+ /* TODO DM_DIRTY_TESS_CDLAYERS ? Maybe not though, since we probably want to switch to looptris ? */
CustomData_merge(&mesh->vdata, &dm->vertData, mask, alloctype,
mesh->totvert);
@@ -2111,8 +655,8 @@ DerivedMesh *CDDM_from_curve(Object *ob)
{
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
return CDDM_from_curve_displist(ob, &disp);
@@ -2153,7 +697,6 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase)
if (alluv) {
const char *uvname = "Orco";
- CustomData_add_layer_named(&cddm->dm.polyData, CD_MTEXPOLY, CD_DEFAULT, NULL, totpoly, uvname);
CustomData_add_layer_named(&cddm->dm.loopData, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
}
@@ -2168,22 +711,18 @@ DerivedMesh *CDDM_from_curve_displist(Object *ob, ListBase *dispbase)
static void loops_to_customdata_corners(
BMesh *bm, CustomData *facedata,
int cdindex, const BMLoop *l3[3],
- int numCol, int numTex)
+ int numCol, int numUV)
{
const BMLoop *l;
- BMFace *f = l3[0]->f;
+// BMFace *f = l3[0]->f;
MTFace *texface;
- MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
int i, j, hasPCol = CustomData_has_layer(&bm->ldata, CD_PREVIEW_MLOOPCOL);
- for (i = 0; i < numTex; i++) {
+ for (i = 0; i < numUV; i++) {
texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
- texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
-
- ME_MTEXFACE_CPY(texface, texpoly);
for (j = 0; j < 3; j++) {
l = l3[j];
@@ -2213,6 +752,8 @@ static void loops_to_customdata_corners(
}
}
+/* TODO(campbell): remove, use BKE_mesh_from_bmesh_for_eval_nomain instead. */
+
/* used for both editbmesh and bmesh */
static DerivedMesh *cddm_from_bmesh_ex(
struct BMesh *bm, const bool use_mdisps,
@@ -2237,7 +778,7 @@ static DerivedMesh *cddm_from_bmesh_ex(
MLoop *mloop = cddm->mloop;
MPoly *mpoly = cddm->mpoly;
int numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
- int numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ int numUV = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
int *index, add_orig;
CustomDataMask mask;
unsigned int i, j;
@@ -2267,7 +808,7 @@ static DerivedMesh *cddm_from_bmesh_ex(
/* add tessellation mface layers */
if (use_tessface) {
- CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, em_tottri);
+ CustomData_from_bmeshpoly(&dm->faceData, &dm->loopData, em_tottri);
}
index = dm->getVertDataArray(dm, CD_ORIGINDEX);
@@ -2339,7 +880,7 @@ static DerivedMesh *cddm_from_bmesh_ex(
/* map mfaces to polygons in the same cddm intentionally */
*index++ = BM_elem_index_get(efa);
- loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex);
+ loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numUV);
test_index_face(mf, &dm->faceData, i, 3);
}
}
@@ -2397,16 +938,13 @@ DerivedMesh *CDDM_from_editbmesh(BMEditMesh *em, const bool use_mdisps, const bo
use_tessface, em->tottri, (const BMLoop *(*)[3])em->looptris);
}
-static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
- const bool need_tessface_data,
- const bool faces_from_tessfaces)
+DerivedMesh *CDDM_copy(DerivedMesh *source)
{
- const bool copy_tessface_data = (faces_from_tessfaces || need_tessface_data);
CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
DerivedMesh *dm = &cddm->dm;
int numVerts = source->numVertData;
int numEdges = source->numEdgeData;
- int numTessFaces = copy_tessface_data ? source->numTessFaceData : 0;
+ int numTessFaces = 0;
int numLoops = source->numLoopData;
int numPolys = source->numPolyData;
@@ -2416,9 +954,6 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
source->getVertDataArray(source, CD_ORIGINDEX);
source->getEdgeDataArray(source, CD_ORIGINDEX);
source->getPolyDataArray(source, CD_ORIGINDEX);
- if (copy_tessface_data) {
- source->getTessFaceDataArray(source, CD_ORIGINDEX);
- }
/* this initializes dm, and copies all non mvert/medge/mface layers */
DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces,
@@ -2430,15 +965,10 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
/* Tessellation data is never copied, so tag it here.
* Only tag dirty layers if we really ignored tessellation faces.
*/
- if (!copy_tessface_data) {
- dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
- }
+ dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
- if (copy_tessface_data) {
- CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces);
- }
/* now add mvert/medge/mface layers */
cddm->mvert = source->dupVertArray(source);
@@ -2447,17 +977,7 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
- if (faces_from_tessfaces || copy_tessface_data) {
- cddm->mface = source->dupTessFaceArray(source);
- CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces);
- }
-
- if (!faces_from_tessfaces) {
- DM_DupPolys(source, dm);
- }
- else {
- CDDM_tessfaces_to_faces(dm);
- }
+ DM_DupPolys(source, dm);
cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
@@ -2465,21 +985,6 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source,
return dm;
}
-DerivedMesh *CDDM_copy(DerivedMesh *source)
-{
- return cddm_copy_ex(source, false, false);
-}
-
-DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source)
-{
- return cddm_copy_ex(source, false, true);
-}
-
-DerivedMesh *CDDM_copy_with_tessface(DerivedMesh *source)
-{
- return cddm_copy_ex(source, true, false);
-}
-
/* note, the CD_ORIGINDEX layers are all 0, so if there is a direct
* relationship between mesh data this needs to be set by the caller. */
DerivedMesh *CDDM_from_template_ex(
@@ -2748,813 +1253,6 @@ void CDDM_calc_loop_normals_spacearr(
#endif
}
-
-void CDDM_calc_normals_tessface(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- float (*face_nors)[3];
-
- if (dm->numVertData == 0) return;
-
- /* we don't want to overwrite any referenced layers */
- cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, dm->numVertData);
-
- /* fill in if it exists */
- face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
- if (!face_nors) {
- face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC, NULL, dm->numTessFaceData);
- }
-
- BKE_mesh_calc_normals_tessface(cddm->mvert, dm->numVertData,
- cddm->mface, dm->numTessFaceData, face_nors);
-
- cddm->dm.dirty &= ~DM_DIRTY_NORMALS;
-}
-
-#if 1
-
-/**
- * Poly compare with vtargetmap
- * Function used by #CDDM_merge_verts.
- * The function compares poly_source after applying vtargetmap, with poly_target.
- * The two polys are identical if they share the same vertices in the same order, or in reverse order,
- * but starting position loopstart may be different.
- * The function is called with direct_reverse=1 for same order (i.e. same normal),
- * and may be called again with direct_reverse=-1 for reverse order.
- * \return 1 if polys are identical, 0 if polys are different.
- */
-static int cddm_poly_compare(
- MLoop *mloop_array,
- MPoly *mpoly_source, MPoly *mpoly_target,
- const int *vtargetmap, const int direct_reverse)
-{
- int vert_source, first_vert_source, vert_target;
- int i_loop_source;
- int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted;
- bool compare_completed = false;
- bool same_loops = false;
-
- MLoop *mloop_source, *mloop_target;
-
- BLI_assert(direct_reverse == 1 || direct_reverse == -1);
-
- i_loop_source = 0;
- mloop_source = mloop_array + mpoly_source->loopstart;
- vert_source = mloop_source->v;
-
- if (vtargetmap[vert_source] != -1) {
- vert_source = vtargetmap[vert_source];
- }
- else {
- /* All source loop vertices should be mapped */
- BLI_assert(false);
- }
-
- /* Find same vertex within mpoly_target's loops */
- mloop_target = mloop_array + mpoly_target->loopstart;
- for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) {
- if (mloop_target->v == vert_source) {
- break;
- }
- }
-
- /* If same vertex not found, then polys cannot be equal */
- if (i_loop_target >= mpoly_target->totloop) {
- return false;
- }
-
- /* Now mloop_source and m_loop_target have one identical vertex */
- /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */
- /* Go around the loop and check that all vertices match in same order */
- /* Skipping source loops when consecutive source vertices are mapped to same target vertex */
-
- i_loop_target_start = i_loop_target;
- i_loop_target_offset = 0;
- first_vert_source = vert_source;
-
- compare_completed = false;
- same_loops = false;
-
- while (!compare_completed) {
-
- vert_target = mloop_target->v;
-
- /* First advance i_loop_source, until it points to different vertex, after mapping applied */
- do {
- i_loop_source++;
-
- if (i_loop_source == mpoly_source->totloop) {
- /* End of loops for source, must match end of loop for target. */
- if (i_loop_target_offset == mpoly_target->totloop - 1) {
- compare_completed = true;
- same_loops = true;
- break; /* Polys are identical */
- }
- else {
- compare_completed = true;
- same_loops = false;
- break; /* Polys are different */
- }
- }
-
- mloop_source++;
- vert_source = mloop_source->v;
-
- if (vtargetmap[vert_source] != -1) {
- vert_source = vtargetmap[vert_source];
- }
- else {
- /* All source loop vertices should be mapped */
- BLI_assert(false);
- }
-
- } while (vert_source == vert_target);
-
- if (compare_completed) {
- break;
- }
-
- /* Now advance i_loop_target as well */
- i_loop_target_offset++;
-
- if (i_loop_target_offset == mpoly_target->totloop) {
- /* End of loops for target only, that means no match */
- /* except if all remaining source vertices are mapped to first target */
- for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) {
- vert_source = vtargetmap[mloop_source->v];
- if (vert_source != first_vert_source) {
- compare_completed = true;
- same_loops = false;
- break;
- }
- }
- if (!compare_completed) {
- same_loops = true;
- }
- break;
- }
-
- /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */
- i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop;
- if (i_loop_target_adjusted < 0) {
- i_loop_target_adjusted += mpoly_target->totloop;
- }
- mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted;
- vert_target = mloop_target->v;
-
- if (vert_target != vert_source) {
- same_loops = false; /* Polys are different */
- break;
- }
- }
- return same_loops;
-}
-
-/* Utility stuff for using GHash with polys */
-
-typedef struct PolyKey {
- int poly_index; /* index of the MPoly within the derived mesh */
- int totloops; /* number of loops in the poly */
- unsigned int hash_sum; /* Sum of all vertices indices */
- unsigned int hash_xor; /* Xor of all vertices indices */
-} PolyKey;
-
-
-static unsigned int poly_gset_hash_fn(const void *key)
-{
- const PolyKey *pk = key;
- return pk->hash_sum;
-}
-
-static bool poly_gset_compare_fn(const void *k1, const void *k2)
-{
- const PolyKey *pk1 = k1;
- const PolyKey *pk2 = k2;
- if ((pk1->hash_sum == pk2->hash_sum) &&
- (pk1->hash_xor == pk2->hash_xor) &&
- (pk1->totloops == pk2->totloops))
- {
- /* Equality - note that this does not mean equality of polys */
- return false;
- }
- else {
- return true;
- }
-}
-
-/**
- * Merge Verts
- *
- * This frees dm, and returns a new one.
- *
- * \param vtargetmap The table that maps vertices to target vertices. a value of -1
- * indicates a vertex is a target, and is to be kept.
- * This array is aligned with 'dm->numVertData'
- * \warning \a vtergatmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported
- * and will likely generate corrupted geometry.
- *
- * \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size)
- *
- * \param merge_mode enum with two modes.
- * - #CDDM_MERGE_VERTS_DUMP_IF_MAPPED
- * When called by the Mirror Modifier,
- * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
- * of faces sharing the same set of vertices)
- * - #CDDM_MERGE_VERTS_DUMP_IF_EQUAL
- * When called by the Array Modifier,
- * In this mode, faces where all vertices are merged are double-checked,
- * to see whether all target vertices actually make up a poly already.
- * Indeed it could be that all of a poly's vertices are merged,
- * but merged to vertices that do not make up a single poly,
- * in which case the original poly should not be dumped.
- * Actually this later behavior could apply to the Mirror Modifier as well, but the additional checks are
- * costly and not necessary in the case of mirror, because each vertex is only merged to its own mirror.
- *
- * \note #CDDM_recalc_tessellation has to run on the returned DM if you want to access tessfaces.
- */
-DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
-{
-// #define USE_LOOPS
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- CDDerivedMesh *cddm2 = NULL;
-
- const int totvert = dm->numVertData;
- const int totedge = dm->numEdgeData;
- const int totloop = dm->numLoopData;
- const int totpoly = dm->numPolyData;
-
- const int totvert_final = totvert - tot_vtargetmap;
-
- MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__);
- int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__);
- int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__);
- STACK_DECLARE(mvert);
- STACK_DECLARE(oldv);
-
- /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require
- * generating new edges, and while in 99% cases we'll still end with less final edges than totedge,
- * cases can be forged that would end requiring more... */
- MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__);
- int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__);
- int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__);
- STACK_DECLARE(medge);
- STACK_DECLARE(olde);
-
- MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__);
- int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__);
-#ifdef USE_LOOPS
- int *newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__);
-#endif
- STACK_DECLARE(mloop);
- STACK_DECLARE(oldl);
-
- MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__);
- int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__);
- STACK_DECLARE(mpoly);
- STACK_DECLARE(oldp);
-
- EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge);
-
- int i, j, c;
-
- PolyKey *poly_keys;
- GSet *poly_gset = NULL;
-
- STACK_INIT(oldv, totvert_final);
- STACK_INIT(olde, totedge);
- STACK_INIT(oldl, totloop);
- STACK_INIT(oldp, totpoly);
-
- STACK_INIT(mvert, totvert_final);
- STACK_INIT(medge, totedge);
- STACK_INIT(mloop, totloop);
- STACK_INIT(mpoly, totpoly);
-
- /* fill newv with destination vertex indices */
- mv = cddm->mvert;
- c = 0;
- for (i = 0; i < totvert; i++, mv++) {
- if (vtargetmap[i] == -1) {
- STACK_PUSH(oldv, i);
- STACK_PUSH(mvert, *mv);
- newv[i] = c++;
- }
- else {
- /* dummy value */
- newv[i] = 0;
- }
- }
-
- /* now link target vertices to destination indices */
- for (i = 0; i < totvert; i++) {
- if (vtargetmap[i] != -1) {
- newv[i] = newv[vtargetmap[i]];
- }
- }
-
- /* Don't remap vertices in cddm->mloop, because we need to know the original
- * indices in order to skip faces with all vertices merged.
- * The "update loop indices..." section further down remaps vertices in mloop.
- */
-
- /* now go through and fix edges and faces */
- med = cddm->medge;
- c = 0;
- for (i = 0; i < totedge; i++, med++) {
- const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
- const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
- if (LIKELY(v1 != v2)) {
- void **val_p;
-
- if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
- newe[i] = POINTER_AS_INT(*val_p);
- }
- else {
- STACK_PUSH(olde, i);
- STACK_PUSH(medge, *med);
- newe[i] = c;
- *val_p = POINTER_FROM_INT(c);
- c++;
- }
- }
- else {
- newe[i] = -1;
- }
- }
-
- if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) {
- /* In this mode, we need to determine, whenever a poly' vertices are all mapped */
- /* if the targets already make up a poly, in which case the new poly is dropped */
- /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */
- PolyKey *mpgh;
- poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__);
- poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly);
- /* Duplicates allowed because our compare function is not pure equality */
- BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
-
- mp = cddm->mpoly;
- mpgh = poly_keys;
- for (i = 0; i < totpoly; i++, mp++, mpgh++) {
- mpgh->poly_index = i;
- mpgh->totloops = mp->totloop;
- ml = cddm->mloop + mp->loopstart;
- mpgh->hash_sum = mpgh->hash_xor = 0;
- for (j = 0; j < mp->totloop; j++, ml++) {
- mpgh->hash_sum += ml->v;
- mpgh->hash_xor ^= ml->v;
- }
- BLI_gset_insert(poly_gset, mpgh);
- }
-
- if (cddm->pmap) {
- MEM_freeN(cddm->pmap);
- MEM_freeN(cddm->pmap_mem);
- }
- /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */
- /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */
- BKE_mesh_vert_poly_map_create(&cddm->pmap, &cddm->pmap_mem,
- cddm->mpoly, cddm->mloop,
- totvert, totpoly, totloop);
- } /* done preparing for fast poly compare */
-
-
- mp = cddm->mpoly;
- mv = cddm->mvert;
- for (i = 0; i < totpoly; i++, mp++) {
- MPoly *mp_new;
-
- ml = cddm->mloop + mp->loopstart;
-
- /* check faces with all vertices merged */
- bool all_vertices_merged = true;
-
- for (j = 0; j < mp->totloop; j++, ml++) {
- if (vtargetmap[ml->v] == -1) {
- all_vertices_merged = false;
- /* This will be used to check for poly using several time the same vert. */
- mv[ml->v].flag &= ~ME_VERT_TMP_TAG;
- }
- else {
- /* This will be used to check for poly using several time the same vert. */
- mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG;
- }
- }
-
- if (UNLIKELY(all_vertices_merged)) {
- if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_MAPPED) {
- /* In this mode, all vertices merged is enough to dump face */
- continue;
- }
- else if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) {
- /* Additional condition for face dump: target vertices must make up an identical face */
- /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
- /* (2) second step is thorough but more costly poly compare */
- int i_poly, v_target;
- bool found = false;
- PolyKey pkey;
-
- /* Use poly_gset for fast (although not 100% certain) identification of same poly */
- /* First, make up a poly_summary structure */
- ml = cddm->mloop + mp->loopstart;
- pkey.hash_sum = pkey.hash_xor = 0;
- pkey.totloops = 0;
- for (j = 0; j < mp->totloop; j++, ml++) {
- v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
- pkey.hash_sum += v_target;
- pkey.hash_xor ^= v_target;
- pkey.totloops++;
- }
- if (BLI_gset_haskey(poly_gset, &pkey)) {
-
- /* There might be a poly that matches this one.
- * We could just leave it there and say there is, and do a "continue".
- * ... but we are checking whether there is an exact poly match.
- * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
- */
-
- /* Consider current loop again */
- ml = cddm->mloop + mp->loopstart;
- /* Consider the target of the loop's first vert */
- v_target = vtargetmap[ml->v];
- /* Now see if v_target belongs to a poly that shares all vertices with source poly,
- * in same order, or reverse order */
-
- for (i_poly = 0; i_poly < cddm->pmap[v_target].count; i_poly++) {
- MPoly *target_poly = cddm->mpoly + *(cddm->pmap[v_target].indices + i_poly);
-
- if (cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, +1) ||
- cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1))
- {
- found = true;
- break;
- }
- }
- if (found) {
- /* Current poly's vertices are mapped to a poly that is strictly identical */
- /* Current poly is dumped */
- continue;
- }
- }
- }
- }
-
-
- /* Here either the poly's vertices were not all merged
- * or they were all merged, but targets do not make up an identical poly,
- * the poly is retained.
- */
- ml = cddm->mloop + mp->loopstart;
-
- c = 0;
- MLoop *last_valid_ml = NULL;
- MLoop *first_valid_ml = NULL;
- bool need_edge_from_last_valid_ml = false;
- bool need_edge_to_first_valid_ml = false;
- int created_edges = 0;
- for (j = 0; j < mp->totloop; j++, ml++) {
- const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v;
-#ifndef NDEBUG
- {
- MLoop *next_ml = cddm->mloop + mp->loopstart + ((j + 1) % mp->totloop);
- uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v;
- med = cddm->medge + ml->e;
- uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
- uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
- BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1));
- }
-#endif
- /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */
- if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) {
- mv[mlv].flag |= ME_VERT_TMP_TAG;
-
- if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) {
- /* We need to create a new edge between last valid loop and this one! */
- void **val_p;
-
- uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
- uint v2 = mlv;
- BLI_assert(v1 != v2);
- if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
- last_valid_ml->e = POINTER_AS_INT(*val_p);
- }
- else {
- const int new_eidx = STACK_SIZE(medge);
- STACK_PUSH(olde, olde[last_valid_ml->e]);
- STACK_PUSH(medge, cddm->medge[last_valid_ml->e]);
- medge[new_eidx].v1 = last_valid_ml->v;
- medge[new_eidx].v2 = ml->v;
- /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
- *val_p = POINTER_FROM_INT(new_eidx);
- created_edges++;
-
- last_valid_ml->e = new_eidx;
- }
- need_edge_from_last_valid_ml = false;
- }
-
-#ifdef USE_LOOPS
- newl[j + mp->loopstart] = STACK_SIZE(mloop);
-#endif
- STACK_PUSH(oldl, j + mp->loopstart);
- last_valid_ml = STACK_PUSH_RET_PTR(mloop);
- *last_valid_ml = *ml;
- if (first_valid_ml == NULL) {
- first_valid_ml = last_valid_ml;
- }
- c++;
-
- /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges
- * in that part of code make remapping later totally unreliable. */
- BLI_assert(newe[ml->e] != -1);
- last_valid_ml->e = newe[ml->e];
- }
- else {
- if (last_valid_ml != NULL) {
- need_edge_from_last_valid_ml = true;
- }
- else {
- need_edge_to_first_valid_ml = true;
- }
- }
- }
- if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) &&
- (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml)))
- {
- /* We need to create a new edge between last valid loop and first valid one! */
- void **val_p;
-
- uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
- uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] : first_valid_ml->v;
- BLI_assert(v1 != v2);
- if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
- last_valid_ml->e = POINTER_AS_INT(*val_p);
- }
- else {
- const int new_eidx = STACK_SIZE(medge);
- STACK_PUSH(olde, olde[last_valid_ml->e]);
- STACK_PUSH(medge, cddm->medge[last_valid_ml->e]);
- medge[new_eidx].v1 = last_valid_ml->v;
- medge[new_eidx].v2 = first_valid_ml->v;
- /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
- *val_p = POINTER_FROM_INT(new_eidx);
- created_edges++;
-
- last_valid_ml->e = new_eidx;
- }
- need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false;
- }
-
- if (UNLIKELY(c == 0)) {
- BLI_assert(created_edges == 0);
- continue;
- }
- else if (UNLIKELY(c < 3)) {
- STACK_DISCARD(oldl, c);
- STACK_DISCARD(mloop, c);
- if (created_edges > 0) {
- for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) {
- BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL);
- }
- STACK_DISCARD(olde, created_edges);
- STACK_DISCARD(medge, created_edges);
- }
- continue;
- }
-
- mp_new = STACK_PUSH_RET_PTR(mpoly);
- *mp_new = *mp;
- mp_new->totloop = c;
- BLI_assert(mp_new->totloop >= 3);
- mp_new->loopstart = STACK_SIZE(mloop) - c;
-
- STACK_PUSH(oldp, i);
- } /* end of the loop that tests polys */
-
-
- if (poly_gset) {
- // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset));
-
- BLI_gset_free(poly_gset, NULL);
- MEM_freeN(poly_keys);
- }
-
- /*create new cddm*/
- cddm2 = (CDDerivedMesh *)CDDM_from_template(
- (DerivedMesh *)cddm, STACK_SIZE(mvert), STACK_SIZE(medge), 0, STACK_SIZE(mloop), STACK_SIZE(mpoly));
-
- /*update edge indices and copy customdata*/
- med = medge;
- for (i = 0; i < cddm2->dm.numEdgeData; i++, med++) {
- BLI_assert(newv[med->v1] != -1);
- med->v1 = newv[med->v1];
- BLI_assert(newv[med->v2] != -1);
- med->v2 = newv[med->v2];
-
- /* Can happen in case vtargetmap contains some double chains, we do not support that. */
- BLI_assert(med->v1 != med->v2);
-
- CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1);
- }
-
- /*update loop indices and copy customdata*/
- ml = mloop;
- for (i = 0; i < cddm2->dm.numLoopData; i++, ml++) {
- /* Edge remapping has already be done in main loop handling part above. */
- BLI_assert(newv[ml->v] != -1);
- ml->v = newv[ml->v];
-
- CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1);
- }
-
- /*copy vertex customdata*/
- mv = mvert;
- for (i = 0; i < cddm2->dm.numVertData; i++, mv++) {
- CustomData_copy_data(&dm->vertData, &cddm2->dm.vertData, oldv[i], i, 1);
- }
-
- /*copy poly customdata*/
- mp = mpoly;
- for (i = 0; i < cddm2->dm.numPolyData; i++, mp++) {
- CustomData_copy_data(&dm->polyData, &cddm2->dm.polyData, oldp[i], i, 1);
- }
-
- /*copy over data. CustomData_add_layer can do this, need to look it up.*/
- memcpy(cddm2->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
- memcpy(cddm2->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
- memcpy(cddm2->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
- memcpy(cddm2->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
-
- MEM_freeN(mvert);
- MEM_freeN(medge);
- MEM_freeN(mloop);
- MEM_freeN(mpoly);
-
- MEM_freeN(newv);
- MEM_freeN(newe);
-#ifdef USE_LOOPS
- MEM_freeN(newl);
-#endif
-
- MEM_freeN(oldv);
- MEM_freeN(olde);
- MEM_freeN(oldl);
- MEM_freeN(oldp);
-
- BLI_edgehash_free(ehash, NULL);
-
- /*free old derivedmesh*/
- dm->needsFree = 1;
- dm->release(dm);
-
- return (DerivedMesh *)cddm2;
-}
-#endif
-
-void CDDM_calc_edges_tessface(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- CustomData edgeData;
- EdgeSetIterator *ehi;
- MFace *mf = cddm->mface;
- MEdge *med;
- EdgeSet *eh;
- int i, *index, numEdges, numFaces = dm->numTessFaceData;
-
- eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces));
-
- for (i = 0; i < numFaces; i++, mf++) {
- BLI_edgeset_add(eh, mf->v1, mf->v2);
- BLI_edgeset_add(eh, mf->v2, mf->v3);
-
- if (mf->v4) {
- BLI_edgeset_add(eh, mf->v3, mf->v4);
- BLI_edgeset_add(eh, mf->v4, mf->v1);
- }
- else {
- BLI_edgeset_add(eh, mf->v3, mf->v1);
- }
- }
-
- numEdges = BLI_edgeset_len(eh);
-
- /* write new edges into a temporary CustomData */
- CustomData_reset(&edgeData);
- CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
- CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
-
- med = CustomData_get_layer(&edgeData, CD_MEDGE);
- index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
-
- for (ehi = BLI_edgesetIterator_new(eh), i = 0;
- BLI_edgesetIterator_isDone(ehi) == false;
- BLI_edgesetIterator_step(ehi), i++, med++, index++)
- {
- BLI_edgesetIterator_getKey(ehi, &med->v1, &med->v2);
-
- med->flag = ME_EDGEDRAW | ME_EDGERENDER;
- *index = ORIGINDEX_NONE;
- }
- BLI_edgesetIterator_free(ehi);
-
- /* free old CustomData and assign new one */
- CustomData_free(&dm->edgeData, dm->numEdgeData);
- dm->edgeData = edgeData;
- dm->numEdgeData = numEdges;
-
- cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
-
- BLI_edgeset_free(eh);
-}
-
-/* warning, this uses existing edges but CDDM_calc_edges_tessface() doesn't */
-void CDDM_calc_edges(DerivedMesh *dm)
-{
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- CustomData edgeData;
- EdgeHashIterator *ehi;
- MPoly *mp = cddm->mpoly;
- MLoop *ml;
- MEdge *med, *origmed;
- EdgeHash *eh;
- unsigned int eh_reserve;
- int v1, v2;
- const int *eindex;
- int i, j, *index;
- const int numFaces = dm->numPolyData;
- const int numLoops = dm->numLoopData;
- int numEdges = dm->numEdgeData;
-
- eindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
- med = cddm->medge;
-
- eh_reserve = max_ii(med ? numEdges : 0, BLI_EDGEHASH_SIZE_GUESS_FROM_LOOPS(numLoops));
- eh = BLI_edgehash_new_ex(__func__, eh_reserve);
- if (med) {
- for (i = 0; i < numEdges; i++, med++) {
- BLI_edgehash_insert(eh, med->v1, med->v2, POINTER_FROM_INT(i + 1));
- }
- }
-
- for (i = 0; i < numFaces; i++, mp++) {
- ml = cddm->mloop + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++) {
- v1 = ml->v;
- v2 = ME_POLY_LOOP_NEXT(cddm->mloop, mp, j)->v;
- BLI_edgehash_reinsert(eh, v1, v2, NULL);
- }
- }
-
- numEdges = BLI_edgehash_len(eh);
-
- /* write new edges into a temporary CustomData */
- CustomData_reset(&edgeData);
- CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
- CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
-
- origmed = cddm->medge;
- med = CustomData_get_layer(&edgeData, CD_MEDGE);
- index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
-
- for (ehi = BLI_edgehashIterator_new(eh), i = 0;
- BLI_edgehashIterator_isDone(ehi) == false;
- BLI_edgehashIterator_step(ehi), ++i, ++med, ++index)
- {
- BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
- j = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
-
- if (j == 0 || !eindex) {
- med->flag = ME_EDGEDRAW | ME_EDGERENDER;
- *index = ORIGINDEX_NONE;
- }
- else {
- med->flag = ME_EDGEDRAW | ME_EDGERENDER | origmed[j - 1].flag;
- *index = eindex[j - 1];
- }
-
- BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(i));
- }
- BLI_edgehashIterator_free(ehi);
-
- /* free old CustomData and assign new one */
- CustomData_free(&dm->edgeData, dm->numEdgeData);
- dm->edgeData = edgeData;
- dm->numEdgeData = numEdges;
-
- cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
-
- mp = cddm->mpoly;
- for (i = 0; i < numFaces; i++, mp++) {
- ml = cddm->mloop + mp->loopstart;
- for (j = 0; j < mp->totloop; j++, ml++) {
- v1 = ml->v;
- v2 = ME_POLY_LOOP_NEXT(cddm->mloop, mp, j)->v;
- ml->e = POINTER_AS_INT(BLI_edgehash_lookup(eh, v1, v2));
- }
- }
-
- BLI_edgehash_free(eh, NULL);
-}
-
void CDDM_lower_num_verts(DerivedMesh *dm, int numVerts)
{
BLI_assert(numVerts >= 0);
@@ -3654,20 +1352,6 @@ MPoly *CDDM_get_polys(DerivedMesh *dm)
return ((CDDerivedMesh *)dm)->mpoly;
}
-void CDDM_tessfaces_to_faces(DerivedMesh *dm)
-{
- /* converts mfaces to mpolys/mloops */
- CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
-
- BKE_mesh_convert_mfaces_to_mpolys_ex(
- NULL, &cddm->dm.faceData, &cddm->dm.loopData, &cddm->dm.polyData,
- cddm->dm.numEdgeData, cddm->dm.numTessFaceData,
- cddm->dm.numLoopData, cddm->dm.numPolyData,
- cddm->medge, cddm->mface,
- &cddm->dm.numLoopData, &cddm->dm.numPolyData,
- &cddm->mloop, &cddm->mpoly);
-}
-
void CDDM_set_mvert(DerivedMesh *dm, MVert *mvert)
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 22fdcb9ea1f..fded9580681 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -33,6 +33,7 @@
#include "DNA_cloth_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
@@ -40,10 +41,14 @@
#include "BLI_edgehash.h"
#include "BLI_linklist.h"
-#include "BKE_cdderivedmesh.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "BKE_bvhutils.h"
#include "BKE_cloth.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
@@ -55,13 +60,19 @@
/* Prototypes for internal functions.
*/
static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*vertexCos)[3]);
-static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm );
-static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float framenr, int first);
+static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh );
+static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, float framenr, int first);
static void cloth_update_springs( ClothModifierData *clmd );
-static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm );
-static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm );
-static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
-static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh );
+static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh );
+static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh );
+static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh );
+
+typedef struct BendSpringRef {
+ int index;
+ int polys;
+ ClothSpring *spring;
+} BendSpringRef;
/******************************************************************************
*
@@ -80,13 +91,18 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->gravity[0] = 0.0;
clmd->sim_parms->gravity[1] = 0.0;
clmd->sim_parms->gravity[2] = -9.81;
- clmd->sim_parms->structural = 15.0;
- clmd->sim_parms->max_struct = 15.0;
- clmd->sim_parms->shear = 15.0;
+ clmd->sim_parms->tension = 15.0;
+ clmd->sim_parms->max_tension = 15.0;
+ clmd->sim_parms->compression = 15.0;
+ clmd->sim_parms->max_compression = 15.0;
+ clmd->sim_parms->shear = 5.0;
+ clmd->sim_parms->max_shear = 5.0;
clmd->sim_parms->bending = 0.5;
clmd->sim_parms->max_bend = 0.5;
+ clmd->sim_parms->tension_damp = 5.0;
+ clmd->sim_parms->compression_damp = 5.0;
+ clmd->sim_parms->shear_damp = 5.0;
clmd->sim_parms->bending_damping = 0.5;
- clmd->sim_parms->Cdis = 5.0;
clmd->sim_parms->Cvi = 1.0;
clmd->sim_parms->mass = 0.3f;
clmd->sim_parms->stepsPerFrame = 5;
@@ -101,7 +117,6 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->timescale = 1.0f; /* speed factor, describes how fast cloth moves */
clmd->sim_parms->time_scale = 1.0f; /* multiplies cloth speed */
clmd->sim_parms->reset = 0;
- clmd->sim_parms->vel_damping = 1.0f; /* 1.0 = no damping, 0.0 = fully dampened */
clmd->coll_parms->self_friction = 5.0;
clmd->coll_parms->friction = 5.0;
@@ -109,8 +124,7 @@ void cloth_init(ClothModifierData *clmd )
clmd->coll_parms->epsilon = 0.015f;
clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED;
clmd->coll_parms->collision_list = NULL;
- clmd->coll_parms->self_loop_count = 1.0;
- clmd->coll_parms->selfepsilon = 0.75;
+ clmd->coll_parms->selfepsilon = 0.015;
clmd->coll_parms->vgroup_selfcol = 0;
/* These defaults are copied from softbody.c's
@@ -129,6 +143,8 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->voxel_cell_size = 0.1f;
+ clmd->sim_parms->bending_model = CLOTH_BENDING_ANGULAR;
+
if (!clmd->sim_parms->effector_weights)
clmd->sim_parms->effector_weights = BKE_add_effector_weights(NULL);
@@ -136,44 +152,6 @@ void cloth_init(ClothModifierData *clmd )
clmd->point_cache->step = 1;
}
-static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon)
-{
- unsigned int i;
- BVHTree *bvhtree;
- Cloth *cloth;
- ClothVertex *verts;
-
- if (!clmd)
- return NULL;
-
- cloth = clmd->clothObject;
-
- if (!cloth)
- return NULL;
-
- verts = cloth->verts;
-
- /* in the moment, return zero if no faces there */
- if (!cloth->mvert_num)
- return NULL;
-
- /* create quadtree with k=26 */
- bvhtree = BLI_bvhtree_new(cloth->mvert_num, epsilon, 4, 6);
-
- /* fill tree */
- for (i = 0; i < cloth->mvert_num; i++, verts++) {
- const float *co;
- co = verts->xold;
-
- BLI_bvhtree_insert(bvhtree, i, co, 1);
- }
-
- /* balance tree */
- BLI_bvhtree_balance(bvhtree);
-
- return bvhtree;
-}
-
static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon)
{
unsigned int i;
@@ -217,14 +195,21 @@ static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon
return bvhtree;
}
-void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
+void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self)
{
unsigned int i = 0;
Cloth *cloth = clmd->clothObject;
- BVHTree *bvhtree = cloth->bvhtree;
+ BVHTree *bvhtree;
ClothVertex *verts = cloth->verts;
const MVertTri *vt;
+ if (self) {
+ bvhtree = cloth->bvhselftree;
+ }
+ else {
+ bvhtree = cloth->bvhtree;
+ }
+
if (!bvhtree)
return;
@@ -236,12 +221,12 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
float co[3][3], co_moving[3][3];
bool ret;
- copy_v3_v3(co[0], verts[vt->tri[0]].txold);
- copy_v3_v3(co[1], verts[vt->tri[1]].txold);
- copy_v3_v3(co[2], verts[vt->tri[2]].txold);
-
/* copy new locations into array */
if (moving) {
+ copy_v3_v3(co[0], verts[vt->tri[0]].txold);
+ copy_v3_v3(co[1], verts[vt->tri[1]].txold);
+ copy_v3_v3(co[2], verts[vt->tri[2]].txold);
+
/* update moving positions */
copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
@@ -250,48 +235,11 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
}
else {
- ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
- }
+ copy_v3_v3(co[0], verts[vt->tri[0]].tx);
+ copy_v3_v3(co[1], verts[vt->tri[1]].tx);
+ copy_v3_v3(co[2], verts[vt->tri[2]].tx);
- /* check if tree is already full */
- if (ret == false) {
- break;
- }
- }
-
- BLI_bvhtree_update_tree(bvhtree);
- }
-}
-
-void bvhselftree_update_from_cloth(ClothModifierData *clmd, bool moving)
-{
- unsigned int i = 0;
- Cloth *cloth = clmd->clothObject;
- BVHTree *bvhtree = cloth->bvhselftree;
- ClothVertex *verts = cloth->verts;
- const MVertTri *vt;
-
- if (!bvhtree)
- return;
-
- vt = cloth->tri;
-
- /* update vertex position in bvh tree */
- if (verts && vt) {
- for (i = 0; i < cloth->mvert_num; i++, verts++) {
- const float *co, *co_moving;
- bool ret;
-
- co = verts->txold;
-
- /* copy new locations into array */
- if (moving) {
- /* update moving positions */
- co_moving = verts->tx;
- ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1);
- }
- else {
- ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1);
+ ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
}
/* check if tree is already full */
@@ -317,7 +265,7 @@ void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_AFTER, framenr);
}
-static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
+static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int framenr)
{
PointCache *cache;
@@ -340,12 +288,13 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
BKE_cloth_solver_set_positions(clmd);
clmd->clothObject->last_frame= MINFRAME-1;
+ clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame;
}
return 1;
}
-static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *result, int framenr)
+static int do_step_cloth(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, Mesh *result, int framenr)
{
ClothVertex *verts = NULL;
Cloth *cloth;
@@ -357,7 +306,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/* simulate 1 frame forward */
cloth = clmd->clothObject;
verts = cloth->verts;
- mvert = result->getVertArray(result);
+ mvert = result->mvert;
/* force any pinned verts to their constrained location. */
for (i = 0; i < clmd->clothObject->mvert_num; i++, verts++) {
@@ -370,7 +319,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
mul_m4_v3(ob->obmat, verts->xconst);
}
- effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights, true);
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, clmd->sim_parms->effector_weights);
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH )
cloth_update_verts ( ob, clmd, result );
@@ -378,19 +327,22 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/* Support for dynamic vertex groups, changing from frame to frame */
cloth_apply_vgroup ( clmd, result );
- if ( clmd->sim_parms->flags & (CLOTH_SIMSETTINGS_FLAG_SEW | CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) )
+ if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH) ||
+ (clmd->sim_parms->vgroup_shrink > 0) || (clmd->sim_parms->shrink_min > 0.0f))
+ {
cloth_update_spring_lengths ( clmd, result );
+ }
cloth_update_springs( clmd );
// TIMEIT_START(cloth_step)
/* call the solver. */
- ret = BPH_cloth_solve(ob, framenr, clmd, effectors);
+ ret = BPH_cloth_solve(depsgraph, ob, framenr, clmd, effectors);
// TIMEIT_END(cloth_step)
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
// printf ( "%f\n", ( float ) tval() );
@@ -400,7 +352,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
/************************************************
* clothModifier_do - main simulation function
************************************************/
-void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, DerivedMesh *dm, float (*vertexCos)[3])
+void clothModifier_do(ClothModifierData *clmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *mesh, float (*vertexCos)[3])
{
PointCache *cache;
PTCacheID pid;
@@ -408,15 +360,14 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
int framenr, startframe, endframe;
int cache_result;
- clmd->scene= scene; /* nice to pass on later :) */
- framenr= (int)scene->r.cfra;
+ framenr = DEG_get_ctime(depsgraph);
cache= clmd->point_cache;
BKE_ptcache_id_from_cloth(&pid, ob, clmd);
BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, &timescale);
clmd->sim_parms->timescale= timescale * clmd->sim_parms->time_scale;
- if (clmd->sim_parms->reset || (clmd->clothObject && dm->getNumVerts(dm) != clmd->clothObject->mvert_num)) {
+ if (clmd->sim_parms->reset || (clmd->clothObject && mesh->totvert != clmd->clothObject->mvert_num)) {
clmd->sim_parms->reset = 0;
cache->flag |= PTCACHE_OUTDATED;
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
@@ -425,9 +376,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
cache->flag &= ~PTCACHE_REDO_NEEDED;
}
- // unused in the moment, calculated separately in implicit.c
- clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
-
/* simulation is only active during a specific period */
if (framenr < startframe) {
BKE_ptcache_invalidate(cache);
@@ -438,12 +386,12 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
}
/* initialize simulation data if it didn't exist already */
- if (!do_init_cloth(ob, clmd, dm, framenr))
+ if (!do_init_cloth(ob, clmd, mesh, framenr))
return;
if (framenr == startframe) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- do_init_cloth(ob, clmd, dm, framenr);
+ do_init_cloth(ob, clmd, mesh, framenr);
BKE_ptcache_validate(cache, framenr);
cache->flag &= ~PTCACHE_REDO_NEEDED;
clmd->clothObject->last_frame= framenr;
@@ -479,9 +427,6 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
return;
}
- if (!can_simulate)
- return;
-
/* if on second frame, write cache for first frame */
if (cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0))
BKE_ptcache_write(&pid, startframe);
@@ -491,7 +436,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
/* do simulation */
BKE_ptcache_validate(cache, framenr);
- if (!do_step_cloth(ob, clmd, dm, framenr)) {
+ if (!do_step_cloth(depsgraph, ob, clmd, mesh, framenr)) {
BKE_ptcache_invalidate(cache);
}
else
@@ -528,6 +473,9 @@ void cloth_free_modifier(ClothModifierData *clmd )
while (search) {
ClothSpring *spring = search->link;
+ MEM_SAFE_FREE(spring->pa);
+ MEM_SAFE_FREE(spring->pb);
+
MEM_freeN ( spring );
search = search->next;
}
@@ -594,6 +542,9 @@ void cloth_free_modifier_extern(ClothModifierData *clmd )
while (search) {
ClothSpring *spring = search->link;
+ MEM_SAFE_FREE(spring->pa);
+ MEM_SAFE_FREE(spring->pb);
+
MEM_freeN ( spring );
search = search->next;
}
@@ -659,15 +610,11 @@ static void cloth_to_object (Object *ob, ClothModifierData *clmd, float (*verte
int cloth_uses_vgroup(ClothModifierData *clmd)
{
- return (((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) ||
- (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) ||
- (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW) ||
- (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF)) &&
- ((clmd->sim_parms->vgroup_mass>0) ||
- (clmd->sim_parms->vgroup_struct>0)||
- (clmd->sim_parms->vgroup_bend>0) ||
- (clmd->sim_parms->vgroup_shrink>0) ||
- (clmd->coll_parms->vgroup_selfcol>0)));
+ return (((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) && (clmd->coll_parms->vgroup_selfcol > 0)) ||
+ (clmd->sim_parms->vgroup_struct > 0) ||
+ (clmd->sim_parms->vgroup_bend > 0) ||
+ (clmd->sim_parms->vgroup_shrink > 0) ||
+ (clmd->sim_parms->vgroup_mass > 0));
}
/**
@@ -675,7 +622,7 @@ int cloth_uses_vgroup(ClothModifierData *clmd)
*
**/
/* can be optimized to do all groups in one loop */
-static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_apply_vgroup ( ClothModifierData *clmd, Mesh *mesh )
{
int i = 0;
int j = 0;
@@ -685,11 +632,11 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
/* float goalfac = 0; */ /* UNUSED */
ClothVertex *verts = NULL;
- if (!clmd || !dm) return;
+ if (!clmd || !mesh) return;
clothObj = clmd->clothObject;
- mvert_num = dm->getNumVerts(dm);
+ mvert_num = mesh->totvert;
verts = clothObj->verts;
@@ -697,7 +644,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
for (i = 0; i < mvert_num; i++, verts++) {
/* Reset Goal values to standard */
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )
+ if (clmd->sim_parms->vgroup_mass > 0)
verts->goal= clmd->sim_parms->defgoal;
else
verts->goal= 0.0f;
@@ -709,10 +656,10 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
verts->flags &= ~CLOTH_VERT_FLAG_PINNED;
verts->flags &= ~CLOTH_VERT_FLAG_NOSELFCOLL;
- dvert = dm->getVertData ( dm, i, CD_MDEFORMVERT );
+ dvert = CustomData_get(&mesh->vdata, i, CD_MDEFORMVERT);
if ( dvert ) {
for ( j = 0; j < dvert->totweight; j++ ) {
- if (( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass-1)) && (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )) {
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass - 1)) {
verts->goal = dvert->dw [j].weight;
/* goalfac= 1.0f; */ /* UNUSED */
@@ -725,15 +672,16 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
verts->flags |= CLOTH_VERT_FLAG_PINNED;
}
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING ) {
- if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_struct-1)) {
- verts->struct_stiff = dvert->dw [j].weight;
- verts->shear_stiff = dvert->dw [j].weight;
- }
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_struct - 1)) {
+ verts->struct_stiff = dvert->dw[j].weight;
+ }
- if ( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_bend-1)) {
- verts->bend_stiff = dvert->dw [j].weight;
- }
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shear - 1)) {
+ verts->shear_stiff = dvert->dw[j].weight;
+ }
+
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_bend - 1)) {
+ verts->bend_stiff = dvert->dw[j].weight;
}
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) {
@@ -743,12 +691,10 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
}
}
}
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) {
- if (clmd->sim_parms->vgroup_shrink > 0) {
- if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
- /* used for linear interpolation between min and max shrink factor based on weight */
- verts->shrink_factor = dvert->dw[j].weight;
- }
+ if (clmd->sim_parms->vgroup_shrink > 0) {
+ if (dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_shrink - 1)) {
+ /* Used for linear interpolation between min and max shrink factor based on weight. */
+ verts->shrink_factor = dvert->dw[j].weight;
}
}
}
@@ -759,31 +705,25 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm )
static float cloth_shrink_factor(ClothModifierData *clmd, ClothVertex *verts, int i1, int i2)
{
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW ) {
- /* linear interpolation between min and max shrink factor based on weight */
- float base = 1.0f - clmd->sim_parms->shrink_min;
- float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
+ /* Linear interpolation between min and max shrink factor based on weight. */
+ float base = 1.0f - clmd->sim_parms->shrink_min;
+ float delta = clmd->sim_parms->shrink_min - clmd->sim_parms->shrink_max;
- float k1 = base + delta * verts[i1].shrink_factor;
- float k2 = base + delta * verts[i2].shrink_factor;
+ float k1 = base + delta * verts[i1].shrink_factor;
+ float k2 = base + delta * verts[i2].shrink_factor;
- /* Use geometrical mean to average two factors since it behaves better
- for diagonals when a rectangle transforms into a trapezoid. */
- return sqrtf(k1 * k2);
- }
- else
- return 1.0f;
+ /* Use geometrical mean to average two factors since it behaves better
+ for diagonals when a rectangle transforms into a trapezoid. */
+ return sqrtf(k1 * k2);
}
-static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *dm, float UNUSED(framenr), int first)
+static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, float UNUSED(framenr), int first)
{
int i = 0;
MVert *mvert = NULL;
ClothVertex *verts = NULL;
float (*shapekey_rest)[3] = NULL;
float tnull[3] = {0, 0, 0};
- Cloth *cloth = NULL;
- float maxdist = 0;
// If we have a clothObject, free it.
if ( clmd->clothObject != NULL ) {
@@ -796,8 +736,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" );
if ( clmd->clothObject ) {
clmd->clothObject->old_solver_type = 255;
- // clmd->clothObject->old_collision_type = 255;
- cloth = clmd->clothObject;
clmd->clothObject->edgeset = NULL;
}
else if (!clmd->clothObject) {
@@ -805,25 +743,25 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
return 0;
}
- // mesh input objects need DerivedMesh
- if ( !dm )
+ // mesh input objects need Mesh
+ if ( !mesh )
return 0;
- cloth_from_mesh ( clmd, dm );
+ cloth_from_mesh ( clmd, mesh );
// create springs
clmd->clothObject->springs = NULL;
clmd->clothObject->numsprings = -1;
if ( clmd->sim_parms->shapekey_rest && !(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH ) )
- shapekey_rest = dm->getVertDataArray ( dm, CD_CLOTH_ORCO );
+ shapekey_rest = CustomData_get_layer(&mesh->vdata, CD_CLOTH_ORCO);
- mvert = dm->getVertArray (dm);
+ mvert = mesh->mvert;
verts = clmd->clothObject->verts;
// set initial values
- for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) {
+ for ( i = 0; i < mesh->totvert; i++, verts++ ) {
if (first) {
copy_v3_v3(verts->x, mvert[i].co);
@@ -841,7 +779,7 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
verts->mass = clmd->sim_parms->mass;
verts->impulse_count = 0;
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )
+ if (clmd->sim_parms->vgroup_mass > 0)
verts->goal= clmd->sim_parms->defgoal;
else
verts->goal= 0.0f;
@@ -861,9 +799,9 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
// apply / set vertex groups
// has to be happen before springs are build!
- cloth_apply_vgroup (clmd, dm);
+ cloth_apply_vgroup (clmd, mesh);
- if ( !cloth_build_springs ( clmd, dm ) ) {
+ if ( !cloth_build_springs ( clmd, mesh ) ) {
cloth_free_modifier ( clmd );
modifier_setError(&(clmd->modifier), "Cannot build springs");
printf("cloth_free_modifier cloth_build_springs\n");
@@ -876,23 +814,18 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
if (!first)
BKE_cloth_solver_set_positions(clmd);
- clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) );
-
- for (i = 0; i < dm->getNumVerts(dm); i++) {
- maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f));
- }
-
- clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist );
+ clmd->clothObject->bvhtree = bvhtree_build_from_cloth (clmd, clmd->coll_parms->epsilon);
+ clmd->clothObject->bvhselftree = bvhtree_build_from_cloth(clmd, clmd->coll_parms->selfepsilon);
return 1;
}
-static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_from_mesh ( ClothModifierData *clmd, Mesh *mesh )
{
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *looptri = dm->getLoopTriArray(dm);
- const unsigned int mvert_num = dm->getNumVerts(dm);
- const unsigned int looptri_num = dm->getNumLoopTri(dm);
+ const MLoop *mloop = mesh->mloop;
+ const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const unsigned int mvert_num = mesh->totvert;
+ const unsigned int looptri_num = mesh->runtime.looptris.len;
/* Allocate our vertices. */
clmd->clothObject->mvert_num = mvert_num;
@@ -913,7 +846,7 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
printf("cloth_free_modifier clmd->clothObject->looptri\n");
return;
}
- DM_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
+ BKE_mesh_runtime_verttri_from_looptri(clmd->clothObject->tri, mloop, looptri, looptri_num);
/* Free the springs since they can't be correct if the vertices
* changed.
@@ -924,7 +857,7 @@ static void cloth_from_mesh ( ClothModifierData *clmd, DerivedMesh *dm )
}
/***************************************************************************************
- * SPRING NETWORK BUILDING IMPLEMENTATION BEGIN
+ * SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION BEGIN
***************************************************************************************/
BLI_INLINE void spring_verts_ordered_set(ClothSpring *spring, int v0, int v1)
@@ -951,13 +884,16 @@ static void cloth_free_edgelist(LinkNodePair *edgelist, unsigned int mvert_num)
}
}
-static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist)
+static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist, BendSpringRef *spring_ref)
{
if ( cloth->springs != NULL ) {
LinkNode *search = cloth->springs;
while (search) {
ClothSpring *spring = search->link;
+ MEM_SAFE_FREE(spring->pa);
+ MEM_SAFE_FREE(spring->pb);
+
MEM_freeN ( spring );
search = search->next;
}
@@ -968,12 +904,49 @@ static void cloth_free_errorsprings(Cloth *cloth, LinkNodePair *edgelist)
cloth_free_edgelist(edgelist, cloth->mvert_num);
+ MEM_SAFE_FREE(spring_ref);
+
if (cloth->edgeset) {
BLI_edgeset_free(cloth->edgeset);
cloth->edgeset = NULL;
}
}
+BLI_INLINE void cloth_bend_poly_dir(ClothVertex *verts, int i, int j, int *inds, int len, float r_dir[3])
+{
+ float cent[3] = {0};
+ float fact = 1.0f / len;
+
+ for (int x = 0; x < len; x++) {
+ madd_v3_v3fl(cent, verts[inds[x]].xrest, fact);
+ }
+
+ normal_tri_v3(r_dir, verts[i].xrest, verts[j].xrest, cent);
+}
+
+static float cloth_spring_angle(ClothVertex *verts, int i, int j, int *i_a, int *i_b, int len_a, int len_b)
+{
+ float dir_a[3], dir_b[3];
+ float tmp[3], vec_e[3];
+ float sin, cos;
+
+ /* Poly vectors. */
+ cloth_bend_poly_dir(verts, j, i, i_a, len_a, dir_a);
+ cloth_bend_poly_dir(verts, i, j, i_b, len_b, dir_b);
+
+ /* Edge vector. */
+ sub_v3_v3v3(vec_e, verts[i].xrest, verts[j].xrest);
+ normalize_v3(vec_e);
+
+ /* Compute angle. */
+ cos = dot_v3v3(dir_a, dir_b);
+
+ cross_v3_v3v3(tmp, dir_a, dir_b);
+ sin = dot_v3v3(tmp, vec_e);
+
+ return atan2f(sin, cos);
+}
+
static void cloth_hair_update_bending_targets(ClothModifierData *clmd)
{
Cloth *cloth = clmd->clothObject;
@@ -998,7 +971,7 @@ static void cloth_hair_update_bending_targets(ClothModifierData *clmd)
ClothHairData *hair_ij, *hair_kl;
bool is_root = spring->kl != prev_mn;
- if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) {
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) {
continue;
}
@@ -1017,24 +990,6 @@ static void cloth_hair_update_bending_targets(ClothModifierData *clmd)
sub_v3_v3v3(dir_new, cloth->verts[spring->mn].x, cloth->verts[spring->kl].x);
normalize_v3(dir_new);
-#if 0
- if (clmd->debug_data && (spring->ij == 0 || spring->ij == 1)) {
- float a[3], b[3];
-
- copy_v3_v3(a, cloth->verts[spring->kl].x);
-// BKE_sim_debug_data_add_dot(clmd->debug_data, cloth_vert ? cloth_vert->x : key->co, 1, 1, 0, "frames", 8246, p, k);
-
- mul_v3_v3fl(b, hair_frame[0], clmd->sim_parms->avg_spring_len);
- BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 1, 0, 0, "frames", 8247, spring->kl, spring->mn);
-
- mul_v3_v3fl(b, hair_frame[1], clmd->sim_parms->avg_spring_len);
- BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 1, 0, "frames", 8248, spring->kl, spring->mn);
-
- mul_v3_v3fl(b, hair_frame[2], clmd->sim_parms->avg_spring_len);
- BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 0, 1, "frames", 8249, spring->kl, spring->mn);
- }
-#endif
-
/* get local targets for kl/mn vertices by putting rest targets into the current frame,
* then multiply with the rest length to get the actual goals
*/
@@ -1073,7 +1028,7 @@ static void cloth_hair_update_bending_rest_targets(ClothModifierData *clmd)
ClothHairData *hair_ij, *hair_kl;
bool is_root = spring->kl != prev_mn;
- if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) {
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_HAIR) {
continue;
}
@@ -1113,18 +1068,24 @@ static void cloth_update_springs( ClothModifierData *clmd )
while (search) {
ClothSpring *spring = search->link;
- spring->stiffness = 0.0f;
+ spring->lin_stiffness = 0.0f;
+
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ if (spring->type & CLOTH_SPRING_TYPE_BENDING) {
+ spring->ang_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ }
+ }
- if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
- spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
+ if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) {
+ spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
}
- else if (spring->type == CLOTH_SPRING_TYPE_SHEAR) {
- spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
+ else if (spring->type & CLOTH_SPRING_TYPE_SHEAR) {
+ spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
}
else if (spring->type == CLOTH_SPRING_TYPE_BENDING) {
- spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
}
- else if (spring->type == CLOTH_SPRING_TYPE_BENDING_ANG) {
+ else if (spring->type == CLOTH_SPRING_TYPE_BENDING_HAIR) {
ClothVertex *v1 = &cloth->verts[spring->ij];
ClothVertex *v2 = &cloth->verts[spring->kl];
if (clmd->hairdata) {
@@ -1132,7 +1093,7 @@ static void cloth_update_springs( ClothModifierData *clmd )
v1->bend_stiff = clmd->hairdata[spring->ij].bending_stiffness;
v2->bend_stiff = clmd->hairdata[spring->kl].bending_stiffness;
}
- spring->stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f;
+ spring->lin_stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f;
}
else if (spring->type == CLOTH_SPRING_TYPE_GOAL) {
/* Warning: Appending NEW goal springs does not work because implicit solver would need reset! */
@@ -1155,27 +1116,27 @@ static void cloth_update_springs( ClothModifierData *clmd )
}
/* Update rest verts, for dynamically deformable cloth */
-static void cloth_update_verts( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
+static void cloth_update_verts( Object *ob, ClothModifierData *clmd, Mesh *mesh )
{
unsigned int i = 0;
- MVert *mvert = dm->getVertArray (dm);
+ MVert *mvert = mesh->mvert;
ClothVertex *verts = clmd->clothObject->verts;
/* vertex count is already ensured to match */
- for ( i = 0; i < dm->getNumVerts(dm); i++, verts++ ) {
+ for ( i = 0; i < mesh->totvert; i++, verts++ ) {
copy_v3_v3(verts->xrest, mvert[i].co);
mul_m4_v3(ob->obmat, verts->xrest);
}
}
-/* Update spring rest lenght, for dynamically deformable cloth */
-static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm )
+/* Update spring rest length, for dynamically deformable cloth */
+static void cloth_update_spring_lengths( ClothModifierData *clmd, Mesh *mesh )
{
Cloth *cloth = clmd->clothObject;
LinkNode *search = cloth->springs;
unsigned int struct_springs = 0;
unsigned int i = 0;
- unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
+ unsigned int mvert_num = (unsigned int)mesh->totvert;
float shrink_factor;
clmd->sim_parms->avg_spring_len = 0.0f;
@@ -1187,16 +1148,23 @@ static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *d
while (search) {
ClothSpring *spring = search->link;
- if ( spring->type != CLOTH_SPRING_TYPE_SEWING ) {
- if ( spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING) )
+ if (spring->type != CLOTH_SPRING_TYPE_SEWING) {
+ if (spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING)) {
shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- else
+ }
+ else {
shrink_factor = 1.0f;
+ }
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
+
+ if (spring->type & CLOTH_SPRING_TYPE_BENDING) {
+ spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl,
+ spring->pa, spring->pb, spring->la, spring->lb);
+ }
}
- if ( spring->type == CLOTH_SPRING_TYPE_STRUCTURAL ) {
+ if (spring->type & CLOTH_SPRING_TYPE_STRUCTURAL) {
clmd->sim_parms->avg_spring_len += spring->restlen;
cloth->verts[spring->ij].avg_spring_len += spring->restlen;
cloth->verts[spring->kl].avg_spring_len += spring->restlen;
@@ -1206,12 +1174,14 @@ static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *d
search = search->next;
}
- if (struct_springs > 0)
+ if (struct_springs > 0) {
clmd->sim_parms->avg_spring_len /= struct_springs;
+ }
for (i = 0; i < mvert_num; i++) {
- if (cloth->verts[i].spring_count > 0)
+ if (cloth->verts[i].spring_count > 0) {
cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
+ }
}
}
@@ -1250,23 +1220,115 @@ void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3]
mul_m3_m3m3(mat, rot, mat);
}
-static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
+/* Add a shear and a bend spring between two verts within a poly. */
+static bool cloth_add_shear_bend_spring(ClothModifierData *clmd, LinkNodePair *edgelist,
+ const MLoop *mloop, const MPoly *mpoly, int i, int j, int k)
+{
+ Cloth *cloth = clmd->clothObject;
+ ClothSpring *spring;
+ const MLoop *tmp_loop;
+ float shrink_factor;
+ int x, y;
+
+ /* Combined shear/bend properties. */
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+
+ if (!spring) {
+ return false;
+ }
+
+ spring_verts_ordered_set(spring,
+ mloop[mpoly[i].loopstart + j].v,
+ mloop[mpoly[i].loopstart + k].v);
+
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
+ spring->type |= CLOTH_SPRING_TYPE_SHEAR;
+ spring->lin_stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
+
+ if (edgelist) {
+ BLI_linklist_append(&edgelist[spring->ij], spring);
+ BLI_linklist_append(&edgelist[spring->kl], spring);
+ }
+
+ /* Bending specific properties. */
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ spring->type |= CLOTH_SPRING_TYPE_BENDING;
+
+ spring->la = k - j + 1;
+ spring->lb = mpoly[i].totloop - k + j + 1;
+
+ spring->pa = MEM_mallocN(sizeof(*spring->pa) * spring->la, "spring poly");
+ if (!spring->pa) {
+ return false;
+ }
+
+ spring->pb = MEM_mallocN(sizeof(*spring->pb) * spring->lb, "spring poly");
+ if (!spring->pb) {
+ return false;
+ }
+
+ tmp_loop = mloop + mpoly[i].loopstart;
+
+ for (x = 0; x < spring->la; x++) {
+ spring->pa[x] = tmp_loop[j + x].v;
+ }
+
+ for (x = 0; x <= j; x++) {
+ spring->pb[x] = tmp_loop[x].v;
+ }
+
+ for (y = k; y < mpoly[i].totloop; x++, y++) {
+ spring->pb[x] = tmp_loop[y].v;
+ }
+
+ spring->mn = -1;
+
+ spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl,
+ spring->pa, spring->pb, spring->la, spring->lb);
+
+ spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f;
+ }
+
+ BLI_linklist_prepend(&cloth->springs, spring);
+
+ return true;
+}
+
+BLI_INLINE bool cloth_bend_set_poly_vert_array(int **poly, int len, const MLoop *mloop)
+{
+ int *p = MEM_mallocN(sizeof(int) * len, "spring poly");
+
+ if (!p) {
+ return false;
+ }
+
+ for (int i = 0; i < len; i++, mloop++) {
+ p[i] = mloop->v;
+ }
+
+ *poly = p;
+
+ return true;
+}
+
+static int cloth_build_springs ( ClothModifierData *clmd, Mesh *mesh )
{
Cloth *cloth = clmd->clothObject;
ClothSpring *spring = NULL, *tspring = NULL, *tspring2 = NULL;
unsigned int struct_springs = 0, shear_springs=0, bend_springs = 0, struct_springs_real = 0;
- unsigned int i = 0;
- unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
- unsigned int numedges = (unsigned int)dm->getNumEdges (dm);
- unsigned int numpolys = (unsigned int)dm->getNumPolys(dm);
+ unsigned int mvert_num = (unsigned int)mesh->totvert;
+ unsigned int numedges = (unsigned int)mesh->totedge;
+ unsigned int numpolys = (unsigned int)mesh->totpoly;
float shrink_factor;
- const MEdge *medge = dm->getEdgeArray(dm);
- const MPoly *mpoly = dm->getPolyArray(dm);
- const MLoop *mloop = dm->getLoopArray(dm);
+ const MEdge *medge = mesh->medge;
+ const MPoly *mpoly = mesh->mpoly;
+ const MLoop *mloop = mesh->mloop;
int index2 = 0; // our second vertex index
- LinkNodePair *edgelist;
+ LinkNodePair *edgelist = NULL;
EdgeSet *edgeset = NULL;
LinkNode *search = NULL, *search2 = NULL;
+ BendSpringRef *spring_ref = NULL;
// error handling
if ( numedges==0 )
@@ -1280,13 +1342,23 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
cloth->springs = NULL;
cloth->edgeset = NULL;
- edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" );
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ spring_ref = MEM_callocN(sizeof(*spring_ref) * numedges, "temp bend spring reference");
- if (!edgelist)
- return 0;
+ if (!spring_ref) {
+ return 0;
+ }
+ }
+ else {
+ edgelist = MEM_callocN(sizeof(*edgelist) * mvert_num, "cloth_edgelist_alloc" );
+
+ if (!edgelist) {
+ return 0;
+ }
+ }
- // structural springs
- for ( i = 0; i < numedges; i++ ) {
+ /* Structural springs. */
+ for (int i = 0; i < numedges; i++) {
spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
if ( spring ) {
@@ -1294,13 +1366,13 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW && medge[i].flag & ME_LOOSEEDGE) {
// handle sewing (loose edges will be pulled together)
spring->restlen = 0.0f;
- spring->stiffness = 1.0f;
+ spring->lin_stiffness = 1.0f;
spring->type = CLOTH_SPRING_TYPE_SEWING;
}
else {
shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
- spring->stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
+ spring->lin_stiffness = (cloth->verts[spring->kl].struct_stiff + cloth->verts[spring->ij].struct_stiff) / 2.0f;
spring->type = CLOTH_SPRING_TYPE_STRUCTURAL;
clmd->sim_parms->avg_spring_len += spring->restlen;
@@ -1315,9 +1387,13 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
struct_springs++;
BLI_linklist_prepend ( &cloth->springs, spring );
+
+ if (spring_ref) {
+ spring_ref[i].spring = spring;
+ }
}
else {
- cloth_free_errorsprings(cloth, edgelist);
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
return 0;
}
}
@@ -1325,86 +1401,147 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
if (struct_springs_real > 0)
clmd->sim_parms->avg_spring_len /= struct_springs_real;
- for (i = 0; i < mvert_num; i++) {
+ for (int i = 0; i < mvert_num; i++) {
if (cloth->verts[i].spring_count > 0)
cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
}
- // shear springs
- for (i = 0; i < numpolys; i++) {
- /* triangle faces already have shear springs due to structural geometry */
- if (mpoly[i].totloop == 4) {
- int j;
+ edgeset = BLI_edgeset_new_ex(__func__, numedges);
+ cloth->edgeset = edgeset;
- for (j = 0; j != 2; j++) {
- spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+ if (numpolys) {
+ for (int i = 0; i < numpolys; i++) {
+ /* Shear springs. */
+ /* Triangle faces already have shear springs due to structural geometry. */
+ if (mpoly[i].totloop > 3) {
+ for (int j = 1; j < mpoly[i].totloop - 1; j++) {
+ if (j > 1) {
+ if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, 0, j)) {
+ shear_springs++;
+
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ bend_springs++;
+ }
+ }
+ else {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+ }
+
+ for (int k = j + 2; k < mpoly[i].totloop; k++) {
+ if (cloth_add_shear_bend_spring(clmd, edgelist, mloop, mpoly, i, j, k)) {
+ shear_springs++;
- if (!spring) {
- cloth_free_errorsprings(cloth, edgelist);
- return 0;
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ bend_springs++;
+ }
+ }
+ else {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+ }
}
+ }
- spring_verts_ordered_set(
- spring,
- mloop[mpoly[i].loopstart + (j + 0)].v,
- mloop[mpoly[i].loopstart + (j + 2)].v);
+ /* Angular bending springs along struct springs. */
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
+ const MLoop *ml = mloop + mpoly[i].loopstart;
- shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
- spring->type = CLOTH_SPRING_TYPE_SHEAR;
- spring->stiffness = (cloth->verts[spring->kl].shear_stiff + cloth->verts[spring->ij].shear_stiff) / 2.0f;
+ for (int j = 0; j < mpoly[i].totloop; j++, ml++) {
+ BendSpringRef *curr_ref = &spring_ref[ml->e];
+ curr_ref->polys++;
- BLI_linklist_append(&edgelist[spring->ij], spring);
- BLI_linklist_append(&edgelist[spring->kl], spring);
+ /* First poly found for this edge, store poly index. */
+ if (curr_ref->polys == 1) {
+ curr_ref->index = i;
+ }
+ /* Second poly found for this edge, add bending data. */
+ else if (curr_ref->polys == 2) {
+ spring = curr_ref->spring;
+
+ spring->type |= CLOTH_SPRING_TYPE_BENDING;
- shear_springs++;
+ spring->la = mpoly[curr_ref->index].totloop;
+ spring->lb = mpoly[i].totloop;
- BLI_linklist_prepend(&cloth->springs, spring);
+ if (!cloth_bend_set_poly_vert_array(&spring->pa, spring->la, &mloop[mpoly[curr_ref->index].loopstart]) ||
+ !cloth_bend_set_poly_vert_array(&spring->pb, spring->lb, &mloop[mpoly[i].loopstart]))
+ {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
+
+ spring->mn = ml->e;
+
+ spring->restang = cloth_spring_angle(cloth->verts, spring->ij, spring->kl,
+ spring->pa, spring->pb, spring->la, spring->lb);
+
+ spring->ang_stiffness = (cloth->verts[spring->ij].bend_stiff + cloth->verts[spring->kl].bend_stiff) / 2.0f;
+
+ bend_springs++;
+ }
+ /* Third poly found for this edge, remove bending data. */
+ else if (curr_ref->polys == 3) {
+ spring = curr_ref->spring;
+
+ spring->type &= ~CLOTH_SPRING_TYPE_BENDING;
+ MEM_freeN(spring->pa);
+ MEM_freeN(spring->pb);
+ spring->pa = NULL;
+ spring->pb = NULL;
+
+ bend_springs--;
+ }
+ }
}
}
- }
- edgeset = BLI_edgeset_new_ex(__func__, numedges);
- cloth->edgeset = edgeset;
+ /* Linear bending springs. */
+ if (clmd->sim_parms->bending_model == CLOTH_BENDING_LINEAR) {
+ search2 = cloth->springs;
- if (numpolys) {
- // bending springs
- search2 = cloth->springs;
- for ( i = struct_springs; i < struct_springs+shear_springs; i++ ) {
- if ( !search2 )
- break;
+ for (int i = struct_springs; i < struct_springs+shear_springs; i++) {
+ if (!search2) {
+ break;
+ }
- tspring2 = search2->link;
- search = edgelist[tspring2->kl].list;
- while ( search ) {
- tspring = search->link;
- index2 = ( ( tspring->ij==tspring2->kl ) ? ( tspring->kl ) : ( tspring->ij ) );
+ tspring2 = search2->link;
+ search = edgelist[tspring2->kl].list;
+
+ while (search) {
+ tspring = search->link;
+ index2 = ((tspring->ij == tspring2->kl) ? (tspring->kl) : (tspring->ij));
+
+ /* Check for existing spring. */
+ /* Check also if startpoint is equal to endpoint. */
+ if ((index2 != tspring2->ij) &&
+ !BLI_edgeset_haskey(edgeset, tspring2->ij, index2))
+ {
+ spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
+
+ if (!spring) {
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
+ return 0;
+ }
- // check for existing spring
- // check also if startpoint is equal to endpoint
- if ((index2 != tspring2->ij) &&
- !BLI_edgeset_haskey(edgeset, tspring2->ij, index2))
- {
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+ spring_verts_ordered_set(spring, tspring2->ij, index2);
+ shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
+ spring->type = CLOTH_SPRING_TYPE_BENDING;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
+ bend_springs++;
- if (!spring) {
- cloth_free_errorsprings(cloth, edgelist);
- return 0;
+ BLI_linklist_prepend(&cloth->springs, spring);
}
- spring_verts_ordered_set(spring, tspring2->ij, index2);
- shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
- spring->type = CLOTH_SPRING_TYPE_BENDING;
- spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
- BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
- bend_springs++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
+ search = search->next;
}
- search = search->next;
+
+ search2 = search2->next;
}
- search2 = search2->next;
}
}
else if (struct_springs > 2) {
@@ -1419,7 +1556,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
if (!spring) {
- cloth_free_errorsprings(cloth, edgelist);
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
return 0;
}
@@ -1427,8 +1564,8 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring->kl = tspring->ij;
spring->mn = tspring->kl;
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
- spring->type = CLOTH_SPRING_TYPE_BENDING_ANG;
- spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ spring->type = CLOTH_SPRING_TYPE_BENDING_HAIR;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
bend_springs++;
BLI_linklist_prepend ( &cloth->springs, spring );
@@ -1456,7 +1593,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
if (!spring) {
- cloth_free_errorsprings(cloth, edgelist);
+ cloth_free_errorsprings(cloth, edgelist, spring_ref);
return 0;
}
@@ -1464,7 +1601,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
spring->kl = tspring->kl;
spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
spring->type = CLOTH_SPRING_TYPE_BENDING;
- spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
bend_springs++;
BLI_linklist_prepend ( &cloth->springs, spring );
@@ -1481,17 +1618,18 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
/* note: the edges may already exist so run reinsert */
/* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */
- for (i = 0; i < numedges; i++) { /* struct springs */
+ for (int i = 0; i < numedges; i++) { /* struct springs */
BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2);
}
- for (i = 0; i < numpolys; i++) { /* edge springs */
+ for (int i = 0; i < numpolys; i++) { /* edge springs */
if (mpoly[i].totloop == 4) {
BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 0].v, mloop[mpoly[i].loopstart + 2].v);
BLI_edgeset_add(edgeset, mloop[mpoly[i].loopstart + 1].v, mloop[mpoly[i].loopstart + 3].v);
}
}
+ MEM_SAFE_FREE(spring_ref);
cloth->numsprings = struct_springs + shear_springs + bend_springs;
@@ -1506,5 +1644,5 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
} /* cloth_build_springs */
/***************************************************************************************
- * SPRING NETWORK BUILDING IMPLEMENTATION END
+ * SPRING NETWORK GPU_BATCH_BUILDING IMPLEMENTATION END
***************************************************************************************/
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
new file mode 100644
index 00000000000..9cec20a8f2b
--- /dev/null
+++ b/source/blender/blenkernel/intern/collection.c
@@ -0,0 +1,1190 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/collection.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_iterator.h"
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_threads.h"
+#include "BLT_translation.h"
+#include "BLI_string_utils.h"
+
+#include "BKE_collection.h"
+#include "BKE_icons.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+
+#include "DNA_ID.h"
+#include "DNA_collection_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MEM_guardedalloc.h"
+
+/******************************** Prototypes ********************************/
+
+static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us);
+static bool collection_child_remove(Collection *parent, Collection *collection);
+static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us);
+static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us);
+
+static CollectionChild *collection_find_child(Collection *parent, Collection *collection);
+static CollectionParent *collection_find_parent(Collection *child, Collection *collection);
+
+static bool collection_find_child_recursive(Collection *parent, Collection *collection);
+
+/***************************** Add Collection *******************************/
+
+/* Add new collection, without view layer syncing. */
+static Collection *collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
+{
+ /* Determine new collection name. */
+ char name[MAX_NAME];
+
+ if (name_custom) {
+ STRNCPY(name, name_custom);
+ }
+ else {
+ BKE_collection_new_name_get(collection_parent, name);
+ }
+
+ /* Create new collection. */
+ Collection *collection = BKE_libblock_alloc(bmain, ID_GR, name, 0);
+
+ /* We increase collection user count when linking to Collections. */
+ id_us_min(&collection->id);
+
+ /* Optionally add to parent collection. */
+ if (collection_parent) {
+ collection_child_add(collection_parent, collection, 0, true);
+ }
+
+ return collection;
+}
+
+/**
+ * Add a collection to a collection ListBase and synchronize all render layers
+ * The ListBase is NULL when the collection is to be added to the master collection
+ */
+Collection *BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
+{
+ Collection *collection = collection_add(bmain, collection_parent, name_custom);
+ BKE_main_collection_sync(bmain);
+ return collection;
+}
+
+/*********************** Free and Delete Collection ****************************/
+
+/** Free (or release) any data used by this collection (does not free the collection itself). */
+void BKE_collection_free(Collection *collection)
+{
+ /* No animdata here. */
+ BKE_previewimg_free(&collection->preview);
+
+ BLI_freelistN(&collection->gobject);
+ BLI_freelistN(&collection->children);
+ BLI_freelistN(&collection->parents);
+
+ BKE_collection_object_cache_free(collection);
+}
+
+/**
+ * Remove a collection, optionally removing its child objects or moving
+ * them to parent collections.
+ */
+bool BKE_collection_delete(Main *bmain, Collection *collection, bool hierarchy)
+{
+ /* Master collection is not real datablock, can't be removed. */
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BLI_assert(!"Scene master collection can't be deleted");
+ return false;
+ }
+
+ if (hierarchy) {
+ /* Remove child objects. */
+ CollectionObject *cob = collection->gobject.first;
+ while (cob != NULL) {
+ collection_object_remove(bmain, collection, cob->ob, true);
+ cob = collection->gobject.first;
+ }
+
+ /* Delete all child collections recursively. */
+ CollectionChild *child = collection->children.first;
+ while (child != NULL) {
+ BKE_collection_delete(bmain, child->collection, hierarchy);
+ child = collection->children.first;
+ }
+ }
+ else {
+ /* Link child collections into parent collection. */
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ Collection *parent = cparent->collection;
+ collection_child_add(parent, child->collection, 0, true);
+ }
+ }
+
+ CollectionObject *cob = collection->gobject.first;
+ while (cob != NULL) {
+ /* Link child object into parent collections. */
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ Collection *parent = cparent->collection;
+ collection_object_add(bmain, parent, cob->ob, 0, true);
+ }
+
+ /* Remove child object. */
+ collection_object_remove(bmain, collection, cob->ob, true);
+ cob = collection->gobject.first;
+ }
+ }
+
+ BKE_libblock_delete(bmain, collection);
+
+ BKE_main_collection_sync(bmain);
+
+ return true;
+}
+
+/***************************** Collection Copy *******************************/
+
+/**
+ * Only copy internal data of Collection ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_collection_copy_data(
+ Main *bmain, Collection *collection_dst, const Collection *collection_src, const int flag)
+{
+ /* Do not copy collection's preview (same behavior as for objects). */
+ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
+ BKE_previewimg_id_copy(&collection_dst->id, &collection_src->id);
+ }
+ else {
+ collection_dst->preview = NULL;
+ }
+
+ collection_dst->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ BLI_listbase_clear(&collection_dst->object_cache);
+
+ BLI_listbase_clear(&collection_dst->gobject);
+ BLI_listbase_clear(&collection_dst->children);
+ BLI_listbase_clear(&collection_dst->parents);
+
+ for (CollectionChild *child = collection_src->children.first; child; child = child->next) {
+ collection_child_add(collection_dst, child->collection, flag, false);
+ }
+ for (CollectionObject *cob = collection_src->gobject.first; cob; cob = cob->next) {
+ collection_object_add(bmain, collection_dst, cob->ob, flag, false);
+ }
+}
+
+/**
+ * Makes a shallow copy of a Collection
+ *
+ * Add a new collection in the same level as the old one, copy any nested collections
+ * but link the objects to the new collection (as oppose to copy them).
+ */
+Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection)
+{
+ /* It's not allowed to copy the master collection. */
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ BLI_assert("!Master collection can't be copied");
+ return NULL;
+ }
+
+ Collection *collection_new;
+ BKE_id_copy_ex(bmain, &collection->id, (ID **)&collection_new, 0, false);
+ id_us_min(&collection_new->id); /* Copying add one user by default, need to get rid of that one. */
+
+ /* Optionally add to parent. */
+ if (parent) {
+ if (collection_child_add(parent, collection_new, 0, true)) {
+ /* Put collection right after existing one. */
+ CollectionChild *child = collection_find_child(parent, collection);
+ CollectionChild *child_new = collection_find_child(parent, collection_new);
+
+ if (child && child_new) {
+ BLI_remlink(&parent->children, child_new);
+ BLI_insertlinkafter(&parent->children, child, child_new);
+ }
+ }
+ }
+
+ BKE_main_collection_sync(bmain);
+
+ return collection_new;
+}
+
+Collection *BKE_collection_copy_master(Main *bmain, Collection *collection, const int flag)
+{
+ BLI_assert(collection->flag & COLLECTION_IS_MASTER);
+
+ Collection *collection_dst = MEM_dupallocN(collection);
+ BKE_collection_copy_data(bmain, collection_dst, collection, flag);
+ return collection_dst;
+}
+
+void BKE_collection_copy_full(Main *UNUSED(bmain), Collection *UNUSED(collection))
+{
+ // TODO: implement full scene copy
+}
+
+void BKE_collection_make_local(Main *bmain, Collection *collection, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &collection->id, true, lib_local);
+}
+
+/********************************* Naming *******************************/
+
+/**
+ * The automatic/fallback name of a new collection.
+ */
+void BKE_collection_new_name_get(Collection *collection_parent, char *rname)
+{
+ char *name;
+
+ if (!collection_parent) {
+ name = BLI_sprintfN("Collection");
+ }
+ else if (collection_parent->flag & COLLECTION_IS_MASTER) {
+ name = BLI_sprintfN("Collection %d", BLI_listbase_count(&collection_parent->children) + 1);
+ }
+ else {
+ const int number = BLI_listbase_count(&collection_parent->children) + 1;
+ const int digits = integer_digits_i(number);
+ const int max_len =
+ sizeof(collection_parent->id.name) - 1 /* NULL terminator */ - (1 + digits) /* " %d" */ - 2 /* ID */;
+ name = BLI_sprintfN("%.*s %d", max_len, collection_parent->id.name + 2, number);
+ }
+
+ BLI_strncpy(rname, name, MAX_NAME);
+ MEM_freeN(name);
+}
+
+/* **************** Object List Cache *******************/
+
+static void collection_object_cache_fill(ListBase *lb, Collection *collection, int parent_restrict)
+{
+ int child_restrict = collection->flag | parent_restrict;
+
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BLI_findptr(lb, cob->ob, offsetof(Base, object));
+
+ if (base == NULL) {
+ base = MEM_callocN(sizeof(Base), "Object Base");
+ base->object = cob->ob;
+ BLI_addtail(lb, base);
+ }
+
+ int object_restrict = base->object->restrictflag;
+
+ if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
+ ((object_restrict & OB_RESTRICT_VIEW) == 0))
+ {
+ base->flag |= BASE_ENABLED_VIEWPORT;
+ }
+
+ if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) &&
+ ((object_restrict & OB_RESTRICT_RENDER) == 0))
+ {
+ base->flag |= BASE_ENABLED_RENDER;
+ }
+ }
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ collection_object_cache_fill(lb, child->collection, child_restrict);
+ }
+}
+
+ListBase BKE_collection_object_cache_get(Collection *collection)
+{
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
+ static ThreadMutex cache_lock = BLI_MUTEX_INITIALIZER;
+
+ BLI_mutex_lock(&cache_lock);
+ if (!(collection->flag & COLLECTION_HAS_OBJECT_CACHE)) {
+ collection_object_cache_fill(&collection->object_cache, collection, 0);
+ collection->flag |= COLLECTION_HAS_OBJECT_CACHE;
+ }
+ BLI_mutex_unlock(&cache_lock);
+ }
+
+ return collection->object_cache;
+}
+
+static void collection_object_cache_free(Collection *collection)
+{
+ /* Clear own cache an for all parents, since those are affected by changes as well. */
+ collection->flag &= ~COLLECTION_HAS_OBJECT_CACHE;
+ BLI_freelistN(&collection->object_cache);
+
+ for (CollectionParent *parent = collection->parents.first; parent; parent = parent->next) {
+ collection_object_cache_free(parent->collection);
+ }
+}
+
+void BKE_collection_object_cache_free(Collection *collection)
+{
+ collection_object_cache_free(collection);
+}
+
+Base *BKE_collection_or_layer_objects(const ViewLayer *view_layer, Collection *collection)
+{
+ if (collection) {
+ return BKE_collection_object_cache_get(collection).first;
+ }
+ else {
+ return FIRSTBASE(view_layer);
+ }
+}
+
+/*********************** Scene Master Collection ***************/
+
+Collection *BKE_collection_master_add()
+{
+ /* Not an actual datablock, but owned by scene. */
+ Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection");
+ STRNCPY(master_collection->id.name, "GRMaster Collection");
+ master_collection->flag |= COLLECTION_IS_MASTER;
+ return master_collection;
+}
+
+Collection *BKE_collection_master(const Scene *scene)
+{
+ return scene->master_collection;
+}
+
+/*********************** Cyclic Checks ************************/
+
+static bool collection_object_cyclic_check_internal(Object *object, Collection *collection)
+{
+ if (object->dup_group) {
+ Collection *dup_collection = object->dup_group;
+ if ((dup_collection->id.tag & LIB_TAG_DOIT) == 0) {
+ /* Cycle already exists in collections, let's prevent further crappyness */
+ return true;
+ }
+ /* flag the object to identify cyclic dependencies in further dupli collections */
+ dup_collection->id.tag &= ~LIB_TAG_DOIT;
+
+ if (dup_collection == collection) {
+ return true;
+ }
+ else {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(dup_collection, collection_object)
+ {
+ if (collection_object_cyclic_check_internal(collection_object, dup_collection)) {
+ return true;
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+
+ /* un-flag the object, it's allowed to have the same collection multiple times in parallel */
+ dup_collection->id.tag |= LIB_TAG_DOIT;
+ }
+
+ return false;
+}
+
+bool BKE_collection_object_cyclic_check(Main *bmain, Object *object, Collection *collection)
+{
+ /* first flag all collections */
+ BKE_main_id_tag_listbase(&bmain->collection, LIB_TAG_DOIT, true);
+
+ return collection_object_cyclic_check_internal(object, collection);
+}
+
+/******************* Collection Object Membership *******************/
+
+bool BKE_collection_has_object(Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ return (BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob)));
+}
+
+bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ const ListBase objects = BKE_collection_object_cache_get(collection);
+ return (BLI_findptr(&objects, ob, offsetof(Base, object)));
+}
+
+Collection *BKE_collection_object_find(Main *bmain, Collection *collection, Object *ob)
+{
+ if (collection)
+ collection = collection->id.next;
+ else
+ collection = bmain->collection.first;
+
+ while (collection) {
+ if (BKE_collection_has_object(collection, ob))
+ return collection;
+ collection = collection->id.next;
+ }
+ return NULL;
+}
+
+bool BKE_collection_is_empty(Collection *collection)
+{
+ return BLI_listbase_is_empty(&collection->gobject) && BLI_listbase_is_empty(&collection->children);
+}
+
+/********************** Collection Objects *********************/
+
+static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us)
+{
+ if (ob->dup_group) {
+ /* Cyclic dependency check. */
+ if (collection_find_child_recursive(ob->dup_group, collection)) {
+ return false;
+ }
+ }
+
+ CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
+ if (cob) {
+ return false;
+ }
+
+ cob = MEM_callocN(sizeof(CollectionObject), __func__);
+ cob->ob = ob;
+ BLI_addtail(&collection->gobject, cob);
+ BKE_collection_object_cache_free(collection);
+
+ if (add_us && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus(&ob->id);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
+ return true;
+}
+
+static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us)
+{
+ CollectionObject *cob = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
+ if (cob == NULL) {
+ return false;
+ }
+
+ BLI_freelinkN(&collection->gobject, cob);
+ BKE_collection_object_cache_free(collection);
+
+ if (free_us) {
+ BKE_libblock_free_us(bmain, ob);
+ }
+ else {
+ id_us_min(&ob->id);
+ }
+
+ DEG_id_tag_update_ex(bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+
+ return true;
+}
+
+/**
+ * Add object to collection
+ */
+bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ if (!collection_object_add(bmain, collection, ob, 0, true)) {
+ return false;
+ }
+
+ if (BKE_collection_is_in_scene(collection)) {
+ BKE_main_collection_sync(bmain);
+ }
+
+ return true;
+}
+
+/**
+ * Add object to all scene collections that reference objects is in
+ * (used to copy objects)
+ */
+void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
+{
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
+ {
+ if (BKE_collection_has_object(collection, ob_src)) {
+ collection_object_add(bmain, collection, ob_dst, 0, true);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ BKE_main_collection_sync(bmain);
+}
+
+/**
+ * Remove object from collection.
+ */
+bool BKE_collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us)
+{
+ if (ELEM(NULL, collection, ob)) {
+ return false;
+ }
+
+ if (!collection_object_remove(bmain, collection, ob, free_us)) {
+ return false;
+ }
+
+ if (BKE_collection_is_in_scene(collection)) {
+ BKE_main_collection_sync(bmain);
+ }
+
+ return true;
+}
+
+/**
+ * Remove object from all collections of scene
+ * \param scene_collection_skip: Don't remove base from this collection.
+ */
+static bool scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us,
+ Collection *collection_skip)
+{
+ bool removed = false;
+
+ BKE_scene_remove_rigidbody_object(bmain, scene, ob);
+
+ FOREACH_SCENE_COLLECTION_BEGIN(scene, collection)
+ {
+ if (collection != collection_skip) {
+ removed |= collection_object_remove(bmain, collection, ob, free_us);
+ }
+ }
+ FOREACH_SCENE_COLLECTION_END;
+
+ BKE_main_collection_sync(bmain);
+
+ return removed;
+}
+
+/**
+ * Remove object from all collections of scene
+ */
+bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us)
+{
+ return scene_collections_object_remove(bmain, scene, ob, free_us, NULL);
+}
+
+/*
+ * Remove all NULL objects from collections.
+ * This is used for library remapping, where these pointers have been set to NULL.
+ * Otherwise this should never happen.
+ */
+static void collection_object_remove_nulls(Collection *collection)
+{
+ bool changed = false;
+
+ for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
+ cob_next = cob->next;
+
+ if (cob->ob == NULL) {
+ BLI_freelinkN(&collection->gobject, cob);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ BKE_collection_object_cache_free(collection);
+ }
+}
+
+void BKE_collections_object_remove_nulls(Main *bmain)
+{
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ collection_object_remove_nulls(scene->master_collection);
+ }
+
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ collection_object_remove_nulls(collection);
+ }
+}
+
+static void collection_null_children_remove(Collection *collection)
+{
+ for (CollectionChild *child = collection->children.first, *child_next = NULL; child; child = child_next) {
+ child_next = child->next;
+
+ if (child->collection == NULL) {
+ BLI_freelinkN(&collection->children, child);
+ }
+ }
+}
+
+static void collection_missing_parents_remove(Collection *collection)
+{
+ for (CollectionParent *parent = collection->parents.first, *parent_next; parent != NULL; parent = parent_next) {
+ parent_next = parent->next;
+
+ if (!collection_find_child(parent->collection, collection)) {
+ BLI_freelinkN(&collection->parents, parent);
+ }
+ }
+}
+
+/**
+ * Remove all NULL children from parent collections of changed \a collection.
+ * This is used for library remapping, where these pointers have been set to NULL.
+ * Otherwise this should never happen.
+ *
+ * \note caller must ensure BKE_main_collection_sync_remap() is called afterwards!
+ *
+ * \param collection may be \a NULL, in which case whole \a bmain database of collections is checked.
+ */
+void BKE_collections_child_remove_nulls(Main *bmain, Collection *collection)
+{
+ if (collection == NULL) {
+ /* We need to do the checks in two steps when more than one collection may be involved,
+ * otherwise we can miss some cases...
+ * Also, master collections are not in bmain, so we also need to loop over scenes.
+ */
+ for (collection = bmain->collection.first; collection != NULL; collection = collection->id.next) {
+ collection_null_children_remove(collection);
+ }
+ for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) {
+ collection_null_children_remove(BKE_collection_master(scene));
+ }
+
+ for (collection = bmain->collection.first; collection != NULL; collection = collection->id.next) {
+ collection_missing_parents_remove(collection);
+ }
+ for (Scene *scene = bmain->scene.first; scene != NULL; scene = scene->id.next) {
+ collection_missing_parents_remove(BKE_collection_master(scene));
+ }
+ }
+ else {
+ for (CollectionParent *parent = collection->parents.first, *parent_next; parent; parent = parent_next) {
+ parent_next = parent->next;
+
+ collection_null_children_remove(parent->collection);
+
+ if (!collection_find_child(parent->collection, collection)) {
+ BLI_freelinkN(&collection->parents, parent);
+ }
+ }
+ }
+}
+
+/**
+ * Move object from a collection into another
+ *
+ * If source collection is NULL move it from all the existing collections.
+ */
+void BKE_collection_object_move(
+ Main *bmain, Scene *scene, Collection *collection_dst, Collection *collection_src, Object *ob)
+{
+ /* In both cases we first add the object, then remove it from the other collections.
+ * Otherwise we lose the original base and whether it was active and selected. */
+ if (collection_src != NULL) {
+ if (BKE_collection_object_add(bmain, collection_dst, ob)) {
+ BKE_collection_object_remove(bmain, collection_src, ob, false);
+ }
+ }
+ else {
+ /* Adding will fail if object is already in collection.
+ * However we still need to remove it from the other collections. */
+ BKE_collection_object_add(bmain, collection_dst, ob);
+ scene_collections_object_remove(bmain, scene, ob, false, collection_dst);
+ }
+}
+
+/***************** Collection Scene Membership ****************/
+
+bool BKE_collection_is_in_scene(Collection *collection)
+{
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return true;
+ }
+
+ for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ if (BKE_collection_is_in_scene(cparent->collection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void BKE_collections_after_lib_link(Main *bmain)
+{
+ /* Update view layer collections to match any changes in linked
+ * collections after file load. */
+ BKE_main_collection_sync(bmain);
+}
+
+/********************** Collection Children *******************/
+
+bool BKE_collection_find_cycle(Collection *new_ancestor, Collection *collection)
+{
+ if (collection == new_ancestor) {
+ return true;
+ }
+
+ for (CollectionParent *parent = new_ancestor->parents.first; parent; parent = parent->next) {
+ if (BKE_collection_find_cycle(parent->collection, collection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static CollectionChild *collection_find_child(Collection *parent, Collection *collection)
+{
+ return BLI_findptr(&parent->children, collection, offsetof(CollectionChild, collection));
+}
+
+static bool collection_find_child_recursive(Collection *parent, Collection *collection)
+{
+ for (CollectionChild *child = parent->children.first; child; child = child->next) {
+ if (child->collection == collection) {
+ return true;
+ }
+
+ if (collection_find_child_recursive(child->collection, collection)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static CollectionParent *collection_find_parent(Collection *child, Collection *collection)
+{
+ return BLI_findptr(&child->parents, collection, offsetof(CollectionParent, collection));
+}
+
+static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us)
+{
+ CollectionChild *child = collection_find_child(parent, collection);
+ if (child) {
+ return false;
+ }
+ if (BKE_collection_find_cycle(parent, collection)) {
+ return false;
+ }
+
+ child = MEM_callocN(sizeof(CollectionChild), "CollectionChild");
+ child->collection = collection;
+ BLI_addtail(&parent->children, child);
+
+ /* Don't add parent links for depsgraph datablocks, these are not kept in sync. */
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ CollectionParent *cparent = MEM_callocN(sizeof(CollectionParent), "CollectionParent");
+ cparent->collection = parent;
+ BLI_addtail(&collection->parents, cparent);
+ }
+
+ if (add_us) {
+ id_us_plus(&collection->id);
+ }
+
+ BKE_collection_object_cache_free(parent);
+
+ return true;
+}
+
+static bool collection_child_remove(Collection *parent, Collection *collection)
+{
+ CollectionChild *child = collection_find_child(parent, collection);
+ if (child == NULL) {
+ return false;
+ }
+
+ CollectionParent *cparent = collection_find_parent(collection, parent);
+ BLI_freelinkN(&collection->parents, cparent);
+ BLI_freelinkN(&parent->children, child);
+
+ id_us_min(&collection->id);
+
+ BKE_collection_object_cache_free(parent);
+
+ return true;
+}
+
+bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child)
+{
+ if (!collection_child_add(parent, child, 0, true)) {
+ return false;
+ }
+
+ BKE_main_collection_sync(bmain);
+ return true;
+}
+
+bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
+{
+ if (!collection_child_remove(parent, child)) {
+ return false;
+ }
+
+ BKE_main_collection_sync(bmain);
+ return true;
+}
+
+/********************** Collection index *********************/
+
+static Collection *collection_from_index_recursive(Collection *collection, const int index, int *index_current)
+{
+ if (index == (*index_current)) {
+ return collection;
+ }
+
+ (*index_current)++;
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ Collection *nested = collection_from_index_recursive(child->collection, index, index_current);
+ if (nested != NULL) {
+ return nested;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Return Scene Collection for a given index.
+ *
+ * The index is calculated from top to bottom counting the children before the siblings.
+ */
+Collection *BKE_collection_from_index(Scene *scene, const int index)
+{
+ int index_current = 0;
+ Collection *master_collection = BKE_collection_master(scene);
+ return collection_from_index_recursive(master_collection, index, &index_current);
+}
+
+static bool collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
+{
+ bool changed = false;
+
+ if (collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
+
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+
+ if (base) {
+ if (deselect) {
+ if (base->flag & BASE_SELECTED) {
+ base->flag &= ~BASE_SELECTED;
+ changed = true;
+ }
+ }
+ else {
+ if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
+ base->flag |= BASE_SELECTED;
+ changed = true;
+ }
+ }
+ }
+ }
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ if (collection_objects_select(view_layer, collection, deselect)) {
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+/**
+ * Select all the objects in this Collection (and its nested collections) for this ViewLayer.
+ * Return true if any object was selected.
+ */
+bool BKE_collection_objects_select(ViewLayer *view_layer, Collection *collection, bool deselect)
+{
+ LayerCollection *layer_collection = BKE_layer_collection_first_from_scene_collection(view_layer, collection);
+
+ if (layer_collection != NULL) {
+ return BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
+ }
+ else {
+ return collection_objects_select(view_layer, collection, deselect);
+ }
+}
+
+/***************** Collection move (outliner drag & drop) *********************/
+
+bool BKE_collection_move(Main *bmain,
+ Collection *to_parent,
+ Collection *from_parent,
+ Collection *relative,
+ bool relative_after,
+ Collection *collection)
+{
+ if (collection->flag & COLLECTION_IS_MASTER) {
+ return false;
+ }
+ if (BKE_collection_find_cycle(to_parent, collection)) {
+ return false;
+ }
+
+ /* Move to new parent collection */
+ if (from_parent) {
+ collection_child_remove(from_parent, collection);
+ }
+
+ collection_child_add(to_parent, collection, 0, true);
+
+ /* Move to specified location under parent. */
+ if (relative) {
+ CollectionChild *child = collection_find_child(to_parent, collection);
+ CollectionChild *relative_child = collection_find_child(to_parent, relative);
+
+ if (relative_child) {
+ BLI_remlink(&to_parent->children, child);
+
+ if (relative_after) {
+ BLI_insertlinkafter(&to_parent->children, relative_child, child);
+ }
+ else {
+ BLI_insertlinkbefore(&to_parent->children, relative_child, child);
+ }
+
+ BKE_collection_object_cache_free(to_parent);
+ }
+ }
+
+ BKE_main_collection_sync(bmain);
+
+ return true;
+}
+
+/**************************** Iterators ******************************/
+
+/* scene collection iteractor */
+
+typedef struct CollectionsIteratorData {
+ Scene *scene;
+ void **array;
+ int tot, cur;
+} CollectionsIteratorData;
+
+static void scene_collection_callback(Collection *collection, BKE_scene_collections_Cb callback, void *data)
+{
+ callback(collection, data);
+
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ scene_collection_callback(child->collection, callback, data);
+ }
+}
+
+static void scene_collections_count(Collection *UNUSED(collection), void *data)
+{
+ int *tot = data;
+ (*tot)++;
+}
+
+static void scene_collections_build_array(Collection *collection, void *data)
+{
+ Collection ***array = data;
+ **array = collection;
+ (*array)++;
+}
+
+static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot)
+{
+ Collection *collection;
+ Collection **array;
+
+ *collections_array = NULL;
+ *tot = 0;
+
+ if (scene == NULL) {
+ return;
+ }
+
+ collection = BKE_collection_master(scene);
+ BLI_assert(collection != NULL);
+ scene_collection_callback(collection, scene_collections_count, tot);
+
+ if (*tot == 0)
+ return;
+
+ *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray");
+ scene_collection_callback(collection, scene_collections_build_array, &array);
+}
+
+/**
+ * Only use this in non-performance critical situations
+ * (it iterates over all scene collections twice)
+ */
+void BKE_scene_collections_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ Scene *scene = data_in;
+ CollectionsIteratorData *data = MEM_callocN(sizeof(CollectionsIteratorData), __func__);
+
+ data->scene = scene;
+ iter->data = data;
+ iter->valid = true;
+
+ scene_collections_array(scene, (Collection ***)&data->array, &data->tot);
+ BLI_assert(data->tot != 0);
+
+ data->cur = 0;
+ iter->current = data->array[data->cur];
+}
+
+void BKE_scene_collections_iterator_next(struct BLI_Iterator *iter)
+{
+ CollectionsIteratorData *data = iter->data;
+
+ if (++data->cur < data->tot) {
+ iter->current = data->array[data->cur];
+ }
+ else {
+ iter->valid = false;
+ }
+}
+
+void BKE_scene_collections_iterator_end(struct BLI_Iterator *iter)
+{
+ CollectionsIteratorData *data = iter->data;
+
+ if (data) {
+ if (data->array) {
+ MEM_freeN(data->array);
+ }
+ MEM_freeN(data);
+ }
+ iter->valid = false;
+}
+
+
+/* scene objects iteractor */
+
+typedef struct SceneObjectsIteratorData {
+ GSet *visited;
+ CollectionObject *cob_next;
+ BLI_Iterator scene_collection_iter;
+} SceneObjectsIteratorData;
+
+void BKE_scene_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ Scene *scene = data_in;
+ SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __func__);
+ iter->data = data;
+
+ /* lookup list ot make sure each object is object called once */
+ data->visited = BLI_gset_ptr_new(__func__);
+
+ /* we wrap the scenecollection iterator here to go over the scene collections */
+ BKE_scene_collections_iterator_begin(&data->scene_collection_iter, scene);
+
+ Collection *collection = data->scene_collection_iter.current;
+ if (collection->gobject.first != NULL) {
+ iter->current = ((CollectionObject *)collection->gobject.first)->ob;
+ }
+ else {
+ BKE_scene_objects_iterator_next(iter);
+ }
+}
+
+/**
+ * Gets the first unique object in the sequence
+ */
+static CollectionObject *object_base_unique(GSet *gs, CollectionObject *cob)
+{
+ for (; cob != NULL; cob = cob->next) {
+ Object *ob = cob->ob;
+ void **ob_key_p;
+ if (!BLI_gset_ensure_p_ex(gs, ob, &ob_key_p)) {
+ *ob_key_p = ob;
+ return cob;
+ }
+ }
+ return NULL;
+}
+
+void BKE_scene_objects_iterator_next(BLI_Iterator *iter)
+{
+ SceneObjectsIteratorData *data = iter->data;
+ CollectionObject *cob = data->cob_next ? object_base_unique(data->visited, data->cob_next) : NULL;
+
+ if (cob) {
+ data->cob_next = cob->next;
+ iter->current = cob->ob;
+ }
+ else {
+ /* if this is the last object of this ListBase look at the next Collection */
+ Collection *collection;
+ BKE_scene_collections_iterator_next(&data->scene_collection_iter);
+ do {
+ collection = data->scene_collection_iter.current;
+ /* get the first unique object of this collection */
+ CollectionObject *new_cob = object_base_unique(data->visited, collection->gobject.first);
+ if (new_cob) {
+ data->cob_next = new_cob->next;
+ iter->current = new_cob->ob;
+ return;
+ }
+ BKE_scene_collections_iterator_next(&data->scene_collection_iter);
+ } while (data->scene_collection_iter.valid);
+
+ if (!data->scene_collection_iter.valid) {
+ iter->valid = false;
+ }
+ }
+}
+
+void BKE_scene_objects_iterator_end(BLI_Iterator *iter)
+{
+ SceneObjectsIteratorData *data = iter->data;
+ if (data) {
+ BKE_scene_collections_iterator_end(&data->scene_collection_iter);
+ BLI_gset_free(data->visited, NULL);
+ MEM_freeN(data);
+ }
+}
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 1df749ee842..d868a06d134 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -33,8 +33,8 @@
#include "MEM_guardedalloc.h"
#include "DNA_cloth_types.h"
+#include "DNA_collection_types.h"
#include "DNA_effect_types.h"
-#include "DNA_group_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
#include "DNA_scene_types.h"
@@ -43,24 +43,45 @@
#include "BLI_utildefines.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_edgehash.h"
+#include "BLI_task.h"
+#include "BLI_threads.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
#include "BKE_effect.h"
+#include "BKE_layer.h"
#include "BKE_modifier.h"
#include "BKE_scene.h"
-#ifdef WITH_BULLET
-#include "Bullet-C-Api.h"
-#endif
#include "BLI_kdopbvh.h"
#include "BKE_collision.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
+
#ifdef WITH_ELTOPO
#include "eltopo-capi.h"
#endif
+typedef struct ColDetectData {
+ ClothModifierData *clmd;
+ CollisionModifierData *collmd;
+ BVHTreeOverlap *overlap;
+ CollPair *collisions;
+ bool culling;
+ bool use_normal;
+ bool collided;
+} ColDetectData;
+
+typedef struct SelfColDetectData {
+ ClothModifierData *clmd;
+ BVHTreeOverlap *overlap;
+ CollPair *collisions;
+ bool collided;
+} SelfColDetectData;
+
/***********************************
Collision modifier code start
***********************************/
@@ -68,7 +89,7 @@ Collision modifier code start
/* step is limited from 0 (frame start position) to 1 (frame end position) */
void collision_move_object(CollisionModifierData *collmd, float step, float prevstep)
{
- float tv[3] = {0, 0, 0};
+ float oldx[3];
unsigned int i = 0;
/* the collider doesn't move this frame */
@@ -81,15 +102,14 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev
}
for (i = 0; i < collmd->mvert_num; i++) {
- sub_v3_v3v3(tv, collmd->xnew[i].co, collmd->x[i].co);
- VECADDS(collmd->current_x[i].co, collmd->x[i].co, tv, prevstep);
- VECADDS(collmd->current_xnew[i].co, collmd->x[i].co, tv, step);
- sub_v3_v3v3(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co);
+ interp_v3_v3v3(oldx, collmd->x[i].co, collmd->xnew[i].co, prevstep);
+ interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, step);
+ sub_v3_v3v3(collmd->current_v[i].co, collmd->current_x[i].co, oldx);
}
bvhtree_update_from_mvert(
- collmd->bvhtree, collmd->current_x, collmd->current_xnew,
- collmd->tri, collmd->tri_num, true);
+ collmd->bvhtree, collmd->current_x, NULL,
+ collmd->tri, collmd->tri_num, false);
}
BVHTree *bvhtree_build_from_mvert(
@@ -172,6 +192,233 @@ void bvhtree_update_from_mvert(
Collision modifier code end
***********************************/
+BLI_INLINE int next_ind(int i)
+{
+ return (++i < 3) ? i : 0;
+}
+
+static float compute_collision_point(float a1[3], float a2[3], float a3[3], float b1[3], float b2[3], float b3[3],
+ bool culling, bool use_normal, float r_a[3], float r_b[3], float r_vec[3])
+{
+ float a[3][3];
+ float b[3][3];
+ float dist = FLT_MAX;
+ float tmp_co1[3], tmp_co2[3];
+ float isect_a[3], isect_b[3];
+ int isect_count = 0;
+ float tmp, tmp_vec[3];
+ float normal[3], cent[3];
+ bool backside = false;
+
+ copy_v3_v3(a[0], a1);
+ copy_v3_v3(a[1], a2);
+ copy_v3_v3(a[2], a3);
+
+ copy_v3_v3(b[0], b1);
+ copy_v3_v3(b[1], b2);
+ copy_v3_v3(b[2], b3);
+
+ /* Find intersections. */
+ for (int i = 0; i < 3; i++) {
+ if (isect_line_segment_tri_v3(a[i], a[next_ind(i)], b[0], b[1], b[2], &tmp, NULL)) {
+ interp_v3_v3v3(isect_a, a[i], a[next_ind(i)], tmp);
+ isect_count++;
+ }
+ }
+
+ if (isect_count == 0) {
+ for (int i = 0; i < 3; i++) {
+ if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
+ isect_count++;
+ }
+ }
+ }
+ else if (isect_count == 1) {
+ for (int i = 0; i < 3; i++) {
+ if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
+ interp_v3_v3v3(isect_b, b[i], b[next_ind(i)], tmp);
+ break;
+ }
+ }
+ }
+
+ /* Determine collision side. */
+ if (culling) {
+ normal_tri_v3(normal, b[0], b[1], b[2]);
+ mid_v3_v3v3v3(cent, b[0], b[1], b[2]);
+
+ if (isect_count == 2) {
+ backside = true;
+ }
+ else if (isect_count == 0) {
+ for (int i = 0; i < 3; i++) {
+ sub_v3_v3v3(tmp_vec, a[i], cent);
+ if (dot_v3v3(tmp_vec, normal) < 0.0f) {
+ backside = true;
+ break;
+ }
+ }
+ }
+ }
+ else if (use_normal) {
+ normal_tri_v3(normal, b[0], b[1], b[2]);
+ }
+
+ if (isect_count == 1) {
+ /* Edge intersection. */
+ copy_v3_v3(r_a, isect_a);
+ copy_v3_v3(r_b, isect_b);
+
+ if (use_normal) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+ }
+
+ return 0.0f;
+ }
+
+ if (backside) {
+ float maxdist = 0.0f;
+ bool found = false;
+
+ /* Point projections. */
+ for (int i = 0; i < 3; i++) {
+ if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) {
+ if (tmp > maxdist) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ madd_v3_v3v3fl(r_b, a[i], normal, tmp);
+ found = true;
+ }
+ }
+ }
+
+ negate_v3(normal);
+
+ for (int i = 0; i < 3; i++) {
+ if (isect_ray_tri_v3(b[i], normal, a[0], a[1], a[2], &tmp, NULL)) {
+ if (tmp > maxdist) {
+ maxdist = tmp;
+ madd_v3_v3v3fl(r_a, b[i], normal, tmp);
+ copy_v3_v3(r_b, b[i]);
+ found = true;
+ }
+ }
+ }
+
+ negate_v3(normal);
+
+ /* Edge projections. */
+ for (int i = 0; i < 3; i++) {
+ float dir[3];
+
+ sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]);
+ cross_v3_v3v3(dir, tmp_vec, normal);
+
+ for (int j = 0; j < 3; j++) {
+ if (isect_line_plane_v3(tmp_co1, a[j], a[next_ind(j)], b[i], dir) &&
+ point_in_slice_seg(tmp_co1, a[j], a[next_ind(j)]) &&
+ point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)]))
+ {
+ closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]);
+ sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2);
+ tmp = len_v3(tmp_vec);
+
+ if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) {
+ maxdist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ found = true;
+ }
+ }
+ }
+ }
+
+ /* If no point is found, will fallback onto regular proximity test below. */
+ if (found) {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+
+ if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+
+ return 0.0f;
+ }
+ }
+
+ /* Closest point. */
+ for (int i = 0; i < 3; i++) {
+ closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]);
+ tmp = len_squared_v3v3(tmp_co1, a[i]);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, a[i]);
+ copy_v3_v3(r_b, tmp_co1);
+ }
+ }
+
+ for (int i = 0; i < 3; i++) {
+ closest_on_tri_to_point_v3(tmp_co1, b[i], a[0], a[1], a[2]);
+ tmp = len_squared_v3v3(tmp_co1, b[i]);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, b[i]);
+ }
+ }
+
+ /* Closest edge. */
+ if (isect_count == 0) {
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ isect_seg_seg_v3(a[i], a[next_ind(i)], b[j], b[next_ind(j)], tmp_co1, tmp_co2);
+ tmp = len_squared_v3v3(tmp_co1, tmp_co2);
+
+ if (tmp < dist) {
+ dist = tmp;
+ copy_v3_v3(r_a, tmp_co1);
+ copy_v3_v3(r_b, tmp_co2);
+ }
+ }
+ }
+ }
+
+ if (isect_count == 0) {
+ sub_v3_v3v3(r_vec, r_a, r_b);
+ dist = sqrtf(dist);
+ }
+ else {
+ sub_v3_v3v3(r_vec, r_b, r_a);
+ dist = 0.0f;
+ }
+
+ if (culling && use_normal) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else if (use_normal) {
+ if (dot_v3v3(normal, r_vec) >= 0.0f) {
+ copy_v3_v3(r_vec, normal);
+ }
+ else {
+ negate_v3_v3(r_vec, normal);
+ }
+ }
+ else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) {
+ return FLT_MAX;
+ }
+
+ return dist;
+}
+
// w3 is not perfect
static void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3 )
{
@@ -226,141 +473,292 @@ DO_INLINE void collision_interpolateOnTriangle ( float to[3], float v1[3], float
VECADDMUL(to, v3, w3);
}
-static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end )
+static int cloth_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, Object *collob,
+ CollPair *collpair, uint collision_count, const float dt)
{
int result = 0;
Cloth *cloth1;
float w1, w2, w3, u1, u2, u3;
float v1[3], v2[3], relativeVelocity[3];
float magrelVel;
- float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
cloth1 = clmd->clothObject;
- for ( ; collpair != collision_end; collpair++ ) {
+ for (int i = 0; i < collision_count; i++, collpair++) {
float i1[3], i2[3], i3[3];
zero_v3(i1);
zero_v3(i2);
zero_v3(i3);
- /* only handle static collisions here */
- if ( collpair->flag & COLLISION_IN_FUTURE )
+ /* Only handle static collisions here. */
+ if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
continue;
+ }
- /* compute barycentric coordinates for both collision points */
- collision_compute_barycentric ( collpair->pa,
- cloth1->verts[collpair->ap1].txold,
- cloth1->verts[collpair->ap2].txold,
- cloth1->verts[collpair->ap3].txold,
- &w1, &w2, &w3 );
+ /* Compute barycentric coordinates for both collision points. */
+ collision_compute_barycentric(collpair->pa,
+ cloth1->verts[collpair->ap1].tx,
+ cloth1->verts[collpair->ap2].tx,
+ cloth1->verts[collpair->ap3].tx,
+ &w1, &w2, &w3);
- /* was: txold */
- collision_compute_barycentric ( collpair->pb,
- collmd->current_x[collpair->bp1].co,
- collmd->current_x[collpair->bp2].co,
- collmd->current_x[collpair->bp3].co,
- &u1, &u2, &u3 );
+ collision_compute_barycentric(collpair->pb,
+ collmd->current_x[collpair->bp1].co,
+ collmd->current_x[collpair->bp2].co,
+ collmd->current_x[collpair->bp3].co,
+ &u1, &u2, &u3);
/* Calculate relative "velocity". */
- collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 );
+ collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3);
- collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
+ collision_interpolateOnTriangle(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3);
sub_v3_v3v3(relativeVelocity, v2, v1);
/* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
- /* printf("magrelVel: %f\n", magrelVel); */
-
- /* Calculate masses of points.
- * TODO */
-
- /* If v_n_mag < 0 the edges are approaching each other. */
- if ( magrelVel > ALMOST_ZERO ) {
+ /* If magrelVel < 0 the edges are approaching each other. */
+ if (magrelVel > 0.0f) {
/* Calculate Impulse magnitude to stop all motion in normal direction. */
float magtangent = 0, repulse = 0, d = 0;
double impulse = 0.0;
float vrel_t_pre[3];
- float temp[3], spf;
+ float temp[3];
+ float time_multiplier;
- /* calculate tangential velocity */
- copy_v3_v3 ( temp, collpair->normal );
+ /* Calculate tangential velocity. */
+ copy_v3_v3(temp, collpair->normal);
mul_v3_fl(temp, magrelVel);
sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
/* Decrease in magnitude of relative tangential velocity due to coulomb friction
- * in original formula "magrelVel" should be the "change of relative velocity in normal direction" */
- magtangent = min_ff(clmd->coll_parms->friction * 0.01f * magrelVel, len_v3(vrel_t_pre));
+ * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
+ magtangent = min_ff(collob->pd->pdef_cfrict * 0.01f * magrelVel, len_v3(vrel_t_pre));
/* Apply friction impulse. */
if ( magtangent > ALMOST_ZERO ) {
normalize_v3(vrel_t_pre);
- impulse = magtangent / ( 1.0f + w1*w1 + w2*w2 + w3*w3 ); /* 2.0 * */
- VECADDMUL ( i1, vrel_t_pre, w1 * impulse );
- VECADDMUL ( i2, vrel_t_pre, w2 * impulse );
- VECADDMUL ( i3, vrel_t_pre, w3 * impulse );
+ impulse = magtangent / 1.5;
+
+ VECADDMUL(i1, vrel_t_pre, w1 * impulse);
+ VECADDMUL(i2, vrel_t_pre, w2 * impulse);
+ VECADDMUL(i3, vrel_t_pre, w3 * impulse);
}
- /* Apply velocity stopping impulse
- * I_c = m * v_N / 2.0
- * no 2.0 * magrelVel normally, but looks nicer DG */
- impulse = magrelVel / ( 1.0 + w1*w1 + w2*w2 + w3*w3 );
+ /* Apply velocity stopping impulse. */
+ impulse = magrelVel / 1.5f;
- VECADDMUL ( i1, collpair->normal, w1 * impulse );
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
cloth1->verts[collpair->ap1].impulse_count++;
- VECADDMUL ( i2, collpair->normal, w2 * impulse );
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
cloth1->verts[collpair->ap2].impulse_count++;
- VECADDMUL ( i3, collpair->normal, w3 * impulse );
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
cloth1->verts[collpair->ap3].impulse_count++;
- /* Apply repulse impulse if distance too short
- * I_r = -min(dt*kd, m(0, 1d/dt - v_n))
- * DG: this formula ineeds to be changed for this code since we apply impulses/repulses like this:
- * v += impulse; x_new = x + v;
- * We don't use dt!!
- * DG TODO: Fix usage of dt here! */
- spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
+ time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance;
- if ( ( magrelVel < 0.1f*d*spf ) && ( d > ALMOST_ZERO ) ) {
- repulse = MIN2 ( d*1.0f/spf, 0.1f*d*spf - magrelVel );
- /* stay on the safe side and clamp repulse */
- if ( impulse > ALMOST_ZERO )
- repulse = min_ff( repulse, 5.0*impulse );
+ if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
+ repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
+
+ /* Stay on the safe side and clamp repulse. */
+ if (impulse > ALMOST_ZERO) {
+ repulse = min_ff(repulse, 5.0f * impulse);
+ }
+
repulse = max_ff(impulse, repulse);
- impulse = repulse / ( 1.0f + w1*w1 + w2*w2 + w3*w3 ); /* original 2.0 / 0.25 */
- VECADDMUL ( i1, collpair->normal, impulse );
- VECADDMUL ( i2, collpair->normal, impulse );
- VECADDMUL ( i3, collpair->normal, impulse );
+ impulse = repulse / 1.5f;
+
+ VECADDMUL(i1, collpair->normal, impulse);
+ VECADDMUL(i2, collpair->normal, impulse);
+ VECADDMUL(i3, collpair->normal, impulse);
}
result = 1;
}
else {
- /* Apply repulse impulse if distance too short
- * I_r = -min(dt*kd, max(0, 1d/dt - v_n))
- * DG: this formula ineeds to be changed for this code since we apply impulses/repulses like this:
- * v += impulse; x_new = x + v;
- * We don't use dt!! */
- float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
-
- float d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - (float)collpair->distance;
- if ( d > ALMOST_ZERO) {
- /* stay on the safe side and clamp repulse */
- float repulse = d*1.0f/spf;
+ float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+ float d;
+
+ d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance;
+
+ if (d > ALMOST_ZERO) {
+ /* Stay on the safe side and clamp repulse. */
+ float repulse = d / time_multiplier;
+ float impulse = repulse / 4.5f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+
+ cloth1->verts[collpair->ap1].impulse_count++;
+ cloth1->verts[collpair->ap2].impulse_count++;
+ cloth1->verts[collpair->ap3].impulse_count++;
+
+ result = 1;
+ }
+ }
+
+ if (result) {
+ float clamp = clmd->coll_parms->clamp * dt;
+
+ if ((clamp > 0.0f) &&
+ ((len_v3(i1) > clamp) ||
+ (len_v3(i2) > clamp) ||
+ (len_v3(i3) > clamp)))
+ {
+ return 0;
+ }
+
+ for (int j = 0; j < 3; j++) {
+ if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
+ cloth1->verts[collpair->ap1].impulse[j] = i1[j];
+
+ if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
+ cloth1->verts[collpair->ap2].impulse[j] = i2[j];
+
+ if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
+ cloth1->verts[collpair->ap3].impulse[j] = i3[j];
+ }
+ }
+ }
+
+ return result;
+}
+
+static int cloth_selfcollision_response_static(ClothModifierData *clmd, CollPair *collpair,
+ uint collision_count, const float dt)
+{
+ int result = 0;
+ Cloth *cloth1;
+ float w1, w2, w3, u1, u2, u3;
+ float v1[3], v2[3], relativeVelocity[3];
+ float magrelVel;
+
+ cloth1 = clmd->clothObject;
+
+ for (int i = 0; i < collision_count; i++, collpair++) {
+ float i1[3], i2[3], i3[3];
+
+ zero_v3(i1);
+ zero_v3(i2);
+ zero_v3(i3);
+
+ /* Only handle static collisions here. */
+ if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
+ continue;
+ }
+
+ /* Compute barycentric coordinates for both collision points. */
+ collision_compute_barycentric(collpair->pa,
+ cloth1->verts[collpair->ap1].tx,
+ cloth1->verts[collpair->ap2].tx,
+ cloth1->verts[collpair->ap3].tx,
+ &w1, &w2, &w3);
+
+ collision_compute_barycentric(collpair->pb,
+ cloth1->verts[collpair->bp1].tx,
+ cloth1->verts[collpair->bp2].tx,
+ cloth1->verts[collpair->bp3].tx,
+ &u1, &u2, &u3);
+
+ /* Calculate relative "velocity". */
+ collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3);
+
+ collision_interpolateOnTriangle(v2, cloth1->verts[collpair->bp1].tv, cloth1->verts[collpair->bp2].tv, cloth1->verts[collpair->bp3].tv, u1, u2, u3);
+
+ sub_v3_v3v3(relativeVelocity, v2, v1);
+
+ /* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
+ magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
+
+ /* TODO: Impulses should be weighed by mass as this is self col,
+ * this has to be done after mass distribution is implemented. */
+
+ /* If magrelVel < 0 the edges are approaching each other. */
+ if (magrelVel > 0.0f) {
+ /* Calculate Impulse magnitude to stop all motion in normal direction. */
+ float magtangent = 0, repulse = 0, d = 0;
+ double impulse = 0.0;
+ float vrel_t_pre[3];
+ float temp[3], time_multiplier;
- float impulse = repulse / ( 3.0f * ( 1.0f + w1*w1 + w2*w2 + w3*w3 )); /* original 2.0 / 0.25 */
+ /* Calculate tangential velocity. */
+ copy_v3_v3(temp, collpair->normal);
+ mul_v3_fl(temp, magrelVel);
+ sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
+
+ /* Decrease in magnitude of relative tangential velocity due to coulomb friction
+ * in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
+ magtangent = min_ff(clmd->coll_parms->self_friction * 0.01f * magrelVel, len_v3(vrel_t_pre));
- VECADDMUL ( i1, collpair->normal, impulse );
- VECADDMUL ( i2, collpair->normal, impulse );
- VECADDMUL ( i3, collpair->normal, impulse );
+ /* Apply friction impulse. */
+ if (magtangent > ALMOST_ZERO) {
+ normalize_v3(vrel_t_pre);
+
+ impulse = magtangent / 1.5;
+
+ VECADDMUL(i1, vrel_t_pre, w1 * impulse);
+ VECADDMUL(i2, vrel_t_pre, w2 * impulse);
+ VECADDMUL(i3, vrel_t_pre, w3 * impulse);
+ }
+
+ /* Apply velocity stopping impulse. */
+ impulse = magrelVel / 3.0f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ cloth1->verts[collpair->ap1].impulse_count++;
+
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ cloth1->verts[collpair->ap2].impulse_count++;
+
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ cloth1->verts[collpair->ap3].impulse_count++;
+
+ time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+
+ d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
+
+ if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
+ repulse = MIN2 (d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
+
+ if (impulse > ALMOST_ZERO) {
+ repulse = min_ff(repulse, 5.0*impulse);
+ }
+
+ repulse = max_ff(impulse, repulse);
+
+ impulse = repulse / 1.5f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
+ }
+
+ result = 1;
+ }
+ else {
+ float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
+ float d;
+
+ d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
+
+ if ( d > ALMOST_ZERO) {
+ /* Stay on the safe side and clamp repulse. */
+ float repulse = d*1.0f/time_multiplier;
+ float impulse = repulse / 9.0f;
+
+ VECADDMUL(i1, collpair->normal, w1 * impulse);
+ VECADDMUL(i2, collpair->normal, w2 * impulse);
+ VECADDMUL(i3, collpair->normal, w3 * impulse);
cloth1->verts[collpair->ap1].impulse_count++;
cloth1->verts[collpair->ap2].impulse_count++;
@@ -371,20 +769,29 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM
}
if (result) {
- int i = 0;
+ float clamp = clmd->coll_parms->self_clamp * dt;
- for (i = 0; i < 3; i++) {
- if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[i]) < ABS(i1[i]))
- cloth1->verts[collpair->ap1].impulse[i] = i1[i];
+ if ((clamp > 0.0f) &&
+ ((len_v3(i1) > clamp) ||
+ (len_v3(i2) > clamp) ||
+ (len_v3(i3) > clamp)))
+ {
+ return 0;
+ }
- if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[i]) < ABS(i2[i]))
- cloth1->verts[collpair->ap2].impulse[i] = i2[i];
+ for (int j = 0; j < 3; j++) {
+ if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
+ cloth1->verts[collpair->ap1].impulse[j] = i1[j];
- if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[i]) < ABS(i3[i]))
- cloth1->verts[collpair->ap3].impulse[i] = i3[i];
+ if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
+ cloth1->verts[collpair->ap2].impulse[j] = i2[j];
+
+ if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
+ cloth1->verts[collpair->ap3].impulse[j] = i3[j];
}
}
}
+
return result;
}
@@ -392,224 +799,257 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM
# pragma GCC diagnostic pop
#endif
-//Determines collisions on overlap, collisions are written to collpair[i] and collision+number_collision_found is returned
-static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2,
- BVHTreeOverlap *overlap, CollPair *collpair, float UNUSED(dt))
+static void cloth_collision(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
{
- ClothModifierData *clmd = (ClothModifierData *)md1;
- CollisionModifierData *collmd = (CollisionModifierData *) md2;
- /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
+ ColDetectData *data = (ColDetectData *)userdata;
+
+ ClothModifierData *clmd = data->clmd;
+ CollisionModifierData *collmd = data->collmd;
+ CollPair *collpair = data->collisions;
const MVertTri *tri_a, *tri_b;
-#ifdef WITH_BULLET
ClothVertex *verts1 = clmd->clothObject->verts;
-#endif
- double distance = 0;
+ float distance = 0.0f;
float epsilon1 = clmd->coll_parms->epsilon;
- float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
+ float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
+ float pa[3], pb[3], vect[3];
- tri_a = &clmd->clothObject->tri[overlap->indexA];
- tri_b = &collmd->tri[overlap->indexB];
+ tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
+ tri_b = &collmd->tri[data->overlap[index].indexB];
- /* fill face_a */
- collpair->ap1 = tri_a->tri[0];
- collpair->ap2 = tri_a->tri[1];
- collpair->ap3 = tri_a->tri[2];
+ /* Compute distance and normal. */
+ distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx,
+ collmd->current_x[tri_b->tri[0]].co, collmd->current_x[tri_b->tri[1]].co, collmd->current_x[tri_b->tri[2]].co,
+ data->culling, data->use_normal, pa, pb, vect);
- /* fill face_b */
- collpair->bp1 = tri_b->tri[0];
- collpair->bp2 = tri_b->tri[1];
- collpair->bp3 = tri_b->tri[2];
+ if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
+ collpair[index].ap1 = tri_a->tri[0];
+ collpair[index].ap2 = tri_a->tri[1];
+ collpair[index].ap3 = tri_a->tri[2];
- {
+ collpair[index].bp1 = tri_b->tri[0];
+ collpair[index].bp2 = tri_b->tri[1];
+ collpair[index].bp3 = tri_b->tri[2];
-#ifdef WITH_BULLET
- // calc distance + normal
- distance = plNearestPoints (
- verts1[collpair->ap1].txold, verts1[collpair->ap2].txold, verts1[collpair->ap3].txold, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co, collpair->pa, collpair->pb, collpair->vector );
-#else
- // just be sure that we don't add anything
- distance = 2.0 * (double)( epsilon1 + epsilon2 + ALMOST_ZERO );
-#endif
+ copy_v3_v3(collpair[index].pa, pa);
+ copy_v3_v3(collpair[index].pb, pb);
+ copy_v3_v3(collpair[index].vector, vect);
- // distance -1 means no collision result
- if (distance != -1.0 && (distance <= (double)(epsilon1 + epsilon2 + ALMOST_ZERO))) {
- normalize_v3_v3(collpair->normal, collpair->vector);
+ normalize_v3_v3(collpair[index].normal, collpair[index].vector);
- collpair->distance = distance;
- collpair->flag = 0;
- collpair++;
- }/*
- else {
- float w1, w2, w3, u1, u2, u3;
- float v1[3], v2[3], relativeVelocity[3];
+ collpair[index].distance = distance;
+ collpair[index].flag = 0;
+
+ data->collided = true;
+ }
+ else {
+ collpair[index].flag = COLLISION_INACTIVE;
+ }
+}
+
+static void cloth_selfcollision(
+ void *__restrict userdata,
+ const int index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ SelfColDetectData *data = (SelfColDetectData *)userdata;
+
+ ClothModifierData *clmd = data->clmd;
+ CollPair *collpair = data->collisions;
+ const MVertTri *tri_a, *tri_b;
+ ClothVertex *verts1 = clmd->clothObject->verts;
+ float distance = 0.0f;
+ float epsilon = clmd->coll_parms->selfepsilon;
+ float pa[3], pb[3], vect[3];
+
+ tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
+ tri_b = &clmd->clothObject->tri[data->overlap[index].indexB];
+
+ for (uint i = 0; i < 3; i++) {
+ for (uint j = 0; j < 3; j++) {
+ if (tri_a->tri[i] == tri_b->tri[j]) {
+ collpair[index].flag = COLLISION_INACTIVE;
+ return;
+ }
+ }
+ }
+
+ if (((verts1[tri_a->tri[0]].flags & verts1[tri_a->tri[1]].flags & verts1[tri_a->tri[2]].flags) |
+ (verts1[tri_b->tri[0]].flags & verts1[tri_b->tri[1]].flags & verts1[tri_b->tri[2]].flags)) & CLOTH_VERT_FLAG_NOSELFCOLL)
+ {
+ collpair[index].flag = COLLISION_INACTIVE;
+ return;
+ }
- // calc relative velocity
+ /* Compute distance and normal. */
+ distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx,
+ verts1[tri_b->tri[0]].tx, verts1[tri_b->tri[1]].tx, verts1[tri_b->tri[2]].tx,
+ false, false, pa, pb, vect);
- // compute barycentric coordinates for both collision points
- collision_compute_barycentric ( collpair->pa,
- verts1[collpair->ap1].txold,
- verts1[collpair->ap2].txold,
- verts1[collpair->ap3].txold,
- &w1, &w2, &w3 );
+ if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
+ collpair[index].ap1 = tri_a->tri[0];
+ collpair[index].ap2 = tri_a->tri[1];
+ collpair[index].ap3 = tri_a->tri[2];
- // was: txold
- collision_compute_barycentric ( collpair->pb,
- collmd->current_x[collpair->bp1].co,
- collmd->current_x[collpair->bp2].co,
- collmd->current_x[collpair->bp3].co,
- &u1, &u2, &u3 );
+ collpair[index].bp1 = tri_b->tri[0];
+ collpair[index].bp2 = tri_b->tri[1];
+ collpair[index].bp3 = tri_b->tri[2];
- // Calculate relative "velocity".
- collision_interpolateOnTriangle ( v1, verts1[collpair->ap1].tv, verts1[collpair->ap2].tv, verts1[collpair->ap3].tv, w1, w2, w3 );
+ copy_v3_v3(collpair[index].pa, pa);
+ copy_v3_v3(collpair[index].pb, pb);
+ copy_v3_v3(collpair[index].vector, vect);
- collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
+ normalize_v3_v3(collpair[index].normal, collpair[index].vector);
- sub_v3_v3v3(relativeVelocity, v2, v1);
+ collpair[index].distance = distance;
+ collpair[index].flag = 0;
- if (sqrt(dot_v3v3(relativeVelocity, relativeVelocity)) >= distance)
- {
- // check for collision in the future
- collpair->flag |= COLLISION_IN_FUTURE;
- collpair++;
- }
- }*/
+ data->collided = true;
+ }
+ else {
+ collpair[index].flag = COLLISION_INACTIVE;
}
- return collpair;
}
-static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned int *maxobj, Object *ob, Object *self, int level, unsigned int modifier_type)
+static void add_collision_object(ListBase *relations, Object *ob, int level, unsigned int modifier_type)
{
CollisionModifierData *cmd= NULL;
- if (ob == self)
- return;
-
/* only get objects with collision modifier */
if (((modifier_type == eModifierType_Collision) && ob->pd && ob->pd->deflect) || (modifier_type != eModifierType_Collision))
cmd= (CollisionModifierData *)modifiers_findByType(ob, modifier_type);
if (cmd) {
- /* extend array */
- if (*numobj >= *maxobj) {
- *maxobj *= 2;
- *objs= MEM_reallocN(*objs, sizeof(Object *)*(*maxobj));
- }
-
- (*objs)[*numobj] = ob;
- (*numobj)++;
+ CollisionRelation *relation = MEM_callocN(sizeof(CollisionRelation), "CollisionRelation");
+ relation->ob = ob;
+ BLI_addtail(relations, relation);
}
/* objects in dupli groups, one level only for now */
+ /* TODO: this doesn't really work, we are not taking into account the
+ * dupli transforms and can get objects in the list multiple times. */
if (ob->dup_group && level == 0) {
- GroupObject *go;
- Group *group= ob->dup_group;
+ Collection *collection= ob->dup_group;
/* add objects */
- for (go= group->gobject.first; go; go= go->next)
- add_collision_object(objs, numobj, maxobj, go->ob, self, level+1, modifier_type);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, object)
+ {
+ add_collision_object(relations, object, level+1, modifier_type);
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
}
-// return all collision objects in scene
-// collision object will exclude self
-Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli)
+/* Create list of collision relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of colliders during evaluation. */
+ListBase *BKE_collision_relations_create(Depsgraph *depsgraph, Collection *collection, unsigned int modifier_type)
{
- Base *base;
- Object **objs;
- GroupObject *go;
- unsigned int numobj= 0, maxobj= 100;
- int level = dupli ? 0 : 1;
-
- objs= MEM_callocN(sizeof(Object *)*maxobj, "CollisionObjectsArray");
-
- /* gather all collision objects */
- if (group) {
- /* use specified group */
- for (go= group->gobject.first; go; go= go->next)
- add_collision_object(&objs, &numobj, &maxobj, go->ob, self, level, modifier_type);
- }
- else {
- Scene *sce_iter;
- /* add objects in same layer in scene */
- for (SETLOOPER(scene, sce_iter, base)) {
- if ( base->lay & layer )
- add_collision_object(&objs, &numobj, &maxobj, base->object, self, level, modifier_type);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ Base *base = BKE_collection_or_layer_objects(view_layer, collection);
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
+
+ ListBase *relations = MEM_callocN(sizeof(ListBase), "CollisionRelation list");
+ for (; base; base = base->next) {
+ if (base->flag & base_flag) {
+ add_collision_object(relations, base->object, 0, modifier_type);
}
}
- *numcollobj= numobj;
-
- return objs;
+ return relations;
}
-Object **get_collisionobjects(Scene *scene, Object *self, Group *group, unsigned int *numcollobj, unsigned int modifier_type)
+void BKE_collision_relations_free(ListBase *relations)
{
- /* Need to check for active layers, too.
- Otherwise this check fails if the objects are not on the same layer - DG */
- return get_collisionobjects_ext(scene, self, group, self->lay | scene->lay, numcollobj, modifier_type, true);
+ if (relations) {
+ BLI_freelistN(relations);
+ MEM_freeN(relations);
+ }
}
-static void add_collider_cache_object(ListBase **objs, Object *ob, Object *self, int level)
+/* Create effective list of colliders from relations built beforehand.
+ * Self will be excluded. */
+Object **BKE_collision_objects_create(Depsgraph *depsgraph, Object *self, Collection *collection, unsigned int *numcollobj, unsigned int modifier_type)
{
- CollisionModifierData *cmd= NULL;
- ColliderCache *col;
+ ListBase *relations = DEG_get_collision_relations(depsgraph, collection, modifier_type);
- if (ob == self)
- return;
+ if (!relations) {
+ *numcollobj = 0;
+ return NULL;
+ }
- if (ob->pd && ob->pd->deflect)
- cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+ int maxnum = BLI_listbase_count(relations);
+ int num = 0;
+ Object **objects = MEM_callocN(sizeof(Object*) * maxnum, __func__);
- if (cmd && cmd->bvhtree) {
- if (*objs == NULL)
- *objs = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+ for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
- col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
- col->ob = ob;
- col->collmd = cmd;
- /* make sure collider is properly set up */
- collision_move_object(cmd, 1.0, 0.0);
- BLI_addtail(*objs, col);
+ if (ob != self) {
+ objects[num] = ob;
+ num++;
+ }
}
- /* objects in dupli groups, one level only for now */
- if (ob->dup_group && level == 0) {
- GroupObject *go;
- Group *group= ob->dup_group;
+ if (num == 0) {
+ MEM_freeN(objects);
+ objects = NULL;
+ }
- /* add objects */
- for (go= group->gobject.first; go; go= go->next)
- add_collider_cache_object(objs, go->ob, self, level+1);
+ *numcollobj = num;
+ return objects;
+}
+
+void BKE_collision_objects_free(Object **objects)
+{
+ if (objects) {
+ MEM_freeN(objects);
}
}
-ListBase *get_collider_cache(Scene *scene, Object *self, Group *group)
+/* Create effective list of colliders from relations built beforehand.
+ * Self will be excluded. */
+ListBase *BKE_collider_cache_create(Depsgraph *depsgraph, Object *self, Collection *collection)
{
- GroupObject *go;
- ListBase *objs= NULL;
+ ListBase *relations = DEG_get_collision_relations(depsgraph, collection, eModifierType_Collision);
+ ListBase *cache = NULL;
- /* add object in same layer in scene */
- if (group) {
- for (go= group->gobject.first; go; go= go->next)
- add_collider_cache_object(&objs, go->ob, self, 0);
+ if (!relations) {
+ return NULL;
}
- else {
- Scene *sce_iter;
- Base *base;
- /* add objects in same layer in scene */
- for (SETLOOPER(scene, sce_iter, base)) {
- if (!self || (base->lay & self->lay))
- add_collider_cache_object(&objs, base->object, self, 0);
+ for (CollisionRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object*)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
+ if (ob == self) {
+ continue;
+ }
+
+ CollisionModifierData *cmd = (CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision);
+ if (cmd && cmd->bvhtree) {
+ if (cache == NULL) {
+ cache = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+ }
+
+ ColliderCache *col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
+ col->ob = ob;
+ col->collmd = cmd;
+ /* make sure collider is properly set up */
+ collision_move_object(cmd, 1.0, 0.0);
+ BLI_addtail(cache, col);
}
}
- return objs;
+ return cache;
}
-void free_collider_cache(ListBase **colliders)
+void BKE_collider_cache_free(ListBase **colliders)
{
if (*colliders) {
BLI_freelistN(*colliders);
@@ -618,25 +1058,49 @@ void free_collider_cache(ListBase **colliders)
}
}
+static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData * clmd, CollisionModifierData *collmd,
+ CollPair **collisions, int numresult,
+ BVHTreeOverlap *overlap, bool culling, bool use_normal)
+{
+ *collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array");
+
+ ColDetectData data = {.clmd = clmd,
+ .collmd = collmd,
+ .overlap = overlap,
+ .collisions = *collisions,
+ .culling = culling,
+ .use_normal = use_normal,
+ .collided = false};
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = true;
+ BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings);
+
+ return data.collided;
+}
-static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd,
- CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap, double dt)
+static bool cloth_bvh_selfcollisions_nearcheck(ClothModifierData * clmd, CollPair *collisions,
+ int numresult, BVHTreeOverlap *overlap)
{
- int i;
+ SelfColDetectData data = {.clmd = clmd,
+ .overlap = overlap,
+ .collisions = collisions,
+ .collided = false};
- *collisions = (CollPair *) MEM_mallocN(sizeof(CollPair) * numresult * 4, "collision array" ); // * 4 since cloth_collision_static can return more than 1 collision
- *collisions_index = *collisions;
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = true;
+ BLI_task_parallel_range(0, numresult, &data, cloth_selfcollision, &settings);
- for ( i = 0; i < numresult; i++ ) {
- *collisions_index = cloth_collision((ModifierData *)clmd, (ModifierData *)collmd,
- overlap+i, *collisions_index, dt);
- }
+ return data.collided;
}
-static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index)
+static int cloth_bvh_objcollisions_resolve(ClothModifierData * clmd, Object **collobjs, CollPair **collisions,
+ uint *collision_counts, const uint numcollobj, const float dt)
{
Cloth *cloth = clmd->clothObject;
- int i=0, j = 0, /*numfaces = 0, */ mvert_num = 0;
+ int i = 0, j = 0, mvert_num = 0;
ClothVertex *verts = NULL;
int ret = 0;
int result = 0;
@@ -644,26 +1108,68 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
mvert_num = clmd->clothObject->mvert_num;
verts = cloth->verts;
- // process all collisions (calculate impulses, TODO: also repulses if distance too short)
result = 1;
- for ( j = 0; j < 2; j++ ) { /* 5 is just a value that ensures convergence */
+
+ for (j = 0; j < 2; j++) {
result = 0;
- if ( collmd->bvhtree ) {
- result += cloth_collision_response_static ( clmd, collmd, collisions, collisions_index );
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob= collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- // apply impulses in parallel
- if (result) {
- for (i = 0; i < mvert_num; i++) {
- // calculate "velocities" (just xnew = xold + v; no dt in v)
- if (verts[i].impulse_count) {
- // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
- VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
- zero_v3(verts[i].impulse);
- verts[i].impulse_count = 0;
+ if ( collmd->bvhtree ) {
+ result += cloth_collision_response_static(clmd, collmd, collob, collisions[i], collision_counts[i], dt);
+ }
+ }
- ret++;
- }
+ /* Apply impulses in parallel. */
+ if (result) {
+ for (i = 0; i < mvert_num; i++) {
+ // calculate "velocities" (just xnew = xold + v; no dt in v)
+ if (verts[i].impulse_count) {
+ VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
+ VECADD ( verts[i].dcvel, verts[i].dcvel, verts[i].impulse);
+ zero_v3(verts[i].impulse);
+ verts[i].impulse_count = 0;
+
+ ret++;
+ }
+ }
+ }
+ else {
+ break;
+ }
+ }
+ return ret;
+}
+
+static int cloth_bvh_selfcollisions_resolve(ClothModifierData * clmd, CollPair *collisions, int collision_count, const float dt)
+{
+ Cloth *cloth = clmd->clothObject;
+ int i = 0, j = 0, mvert_num = 0;
+ ClothVertex *verts = NULL;
+ int ret = 0;
+ int result = 0;
+
+ mvert_num = clmd->clothObject->mvert_num;
+ verts = cloth->verts;
+
+ for (j = 0; j < 2; j++) {
+ result = 0;
+
+ result += cloth_selfcollision_response_static(clmd, collisions, collision_count, dt);
+
+ /* Apply impulses in parallel. */
+ if (result) {
+ for (i = 0; i < mvert_num; i++) {
+ if (verts[i].impulse_count) {
+ // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
+ VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
+ VECADD ( verts[i].dcvel, verts[i].dcvel, verts[i].impulse);
+ zero_v3(verts[i].impulse);
+ verts[i].impulse_count = 0;
+
+ ret++;
}
}
}
@@ -675,219 +1181,149 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
return ret;
}
-// cloth - object collisions
-int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt )
+int cloth_bvh_collision(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt)
{
- Cloth *cloth= clmd->clothObject;
- BVHTree *cloth_bvh= cloth->bvhtree;
- unsigned int i=0, /* numfaces = 0, */ /* UNUSED */ mvert_num = 0, k, l, j;
- int rounds = 0; // result counts applied collisions; ic is for debug output;
+ Cloth *cloth = clmd->clothObject;
+ BVHTree *cloth_bvh = cloth->bvhtree;
+ uint i = 0, mvert_num = 0;
+ int rounds = 0;
ClothVertex *verts = NULL;
int ret = 0, ret2 = 0;
Object **collobjs = NULL;
unsigned int numcollobj = 0;
+ uint *coll_counts_obj = NULL;
+ BVHTreeOverlap **overlap_obj = NULL;
+ uint coll_count_self = 0;
+ BVHTreeOverlap *overlap_self = NULL;
if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) || cloth_bvh==NULL)
return 0;
verts = cloth->verts;
- /* numfaces = cloth->numfaces; */ /* UNUSED */
mvert_num = cloth->mvert_num;
- ////////////////////////////////////////////////////////////
- // static collisions
- ////////////////////////////////////////////////////////////
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
+ bvhtree_update_from_cloth(clmd, false, false);
- // update cloth bvh
- bvhtree_update_from_cloth ( clmd, 1 ); // 0 means STATIC, 1 means MOVING (see later in this function)
- bvhselftree_update_from_cloth ( clmd, 0 ); // 0 means STATIC, 1 means MOVING (see later in this function)
+ collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
- collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ if (collobjs) {
+ coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts");
+ overlap_obj = MEM_callocN(sizeof(*overlap_obj) * numcollobj, "BVHOverlap");
- if (!collobjs)
- return 0;
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob = collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- /* move object to position (step) in time */
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
+ if (!collmd->bvhtree) {
+ continue;
+ }
- if (!collmd->bvhtree)
- continue;
+ /* Move object to position (step) in time. */
+ collision_move_object(collmd, step + dt, step);
- /* move object to position (step) in time */
- collision_move_object ( collmd, step + dt, step );
+ overlap_obj[i] = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &coll_counts_obj[i], NULL, NULL);
+ }
+ }
}
- do {
- CollPair **collisions, **collisions_index;
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
+ bvhtree_update_from_cloth(clmd, false, true);
+
+ overlap_self = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &coll_count_self, NULL, NULL);
+ }
+ do {
ret2 = 0;
- collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
- collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
+ /* Object collisions. */
+ if ((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) && collobjs) {
+ CollPair **collisions;
+ bool collided = false;
- // check all collision objects
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- BVHTreeOverlap *overlap = NULL;
- unsigned int result = 0;
+ collisions = MEM_callocN(sizeof(CollPair *) * numcollobj, "CollPair");
- if (!collmd->bvhtree)
- continue;
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob = collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- /* search for overlapping collision pairs */
- overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
+ if (!collmd->bvhtree) {
+ continue;
+ }
- // go to next object if no overlap is there
- if ( result && overlap ) {
- /* check if collisions really happen (costly near check) */
- cloth_bvh_objcollisions_nearcheck ( clmd, collmd, &collisions[i],
- &collisions_index[i], result, overlap, dt/(float)clmd->coll_parms->loop_count);
+ if (coll_counts_obj[i] && overlap_obj[i]) {
+ collided = cloth_bvh_objcollisions_nearcheck(clmd, collmd, &collisions[i], coll_counts_obj[i], overlap_obj[i],
+ (collob->pd->flag & PFIELD_CLOTH_USE_CULLING),
+ (collob->pd->flag & PFIELD_CLOTH_USE_NORMAL)) || collided;
+ }
+ }
- // resolve nearby collisions
- ret += cloth_bvh_objcollisions_resolve ( clmd, collmd, collisions[i], collisions_index[i]);
+ if (collided) {
+ ret += cloth_bvh_objcollisions_resolve(clmd, collobjs, collisions, coll_counts_obj, numcollobj, dt);
ret2 += ret;
}
- if ( overlap )
- MEM_freeN ( overlap );
- }
- rounds++;
+ for (i = 0; i < numcollobj; i++) {
+ MEM_SAFE_FREE(collisions[i]);
+ }
- for (i = 0; i < numcollobj; i++) {
- if ( collisions[i] ) MEM_freeN ( collisions[i] );
+ MEM_freeN(collisions);
}
- MEM_freeN(collisions);
- MEM_freeN(collisions_index);
+ /* Self collisions. */
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
+ CollPair *collisions = NULL;
- ////////////////////////////////////////////////////////////
- // update positions
- // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
- ////////////////////////////////////////////////////////////
+ verts = cloth->verts;
+ mvert_num = cloth->mvert_num;
- /* verts come from clmd */
- for (i = 0; i < mvert_num; i++) {
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
- if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
- continue;
+ if (cloth->bvhselftree) {
+ if (coll_count_self && overlap_self) {
+ collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * coll_count_self, "collision array");
+
+ if (cloth_bvh_selfcollisions_nearcheck(clmd, collisions, coll_count_self, overlap_self)) {
+ ret += cloth_bvh_selfcollisions_resolve(clmd, collisions, coll_count_self, dt);
+ ret2 += ret;
+ }
}
+
}
- VECADD ( verts[i].tx, verts[i].txold, verts[i].tv );
+ MEM_SAFE_FREE(collisions);
}
- ////////////////////////////////////////////////////////////
-
-
- ////////////////////////////////////////////////////////////
- // Test on *simple* selfcollisions
- ////////////////////////////////////////////////////////////
- if ( clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) {
- for (l = 0; l < (unsigned int)clmd->coll_parms->self_loop_count; l++) {
- /* TODO: add coll quality rounds again */
- BVHTreeOverlap *overlap = NULL;
- unsigned int result = 0;
-
- // collisions = 1;
- verts = cloth->verts; // needed for openMP
-
- /* numfaces = cloth->numfaces; */ /* UNUSED */
- mvert_num = cloth->mvert_num;
-
- verts = cloth->verts;
-
- if ( cloth->bvhselftree ) {
- // search for overlapping collision pairs
- overlap = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &result, NULL, NULL);
-
- /* Could be parallelized (using BLI_task)... */
- for ( k = 0; k < result; k++ ) {
- float temp[3];
- float length = 0;
- float mindistance;
-
- i = overlap[k].indexA;
- j = overlap[k].indexB;
-
- mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len );
-
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
- if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) &&
- ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) )
- {
- continue;
- }
- }
-
- if ((cloth->verts[i].flags & CLOTH_VERT_FLAG_NOSELFCOLL) ||
- (cloth->verts[j].flags & CLOTH_VERT_FLAG_NOSELFCOLL))
- {
- continue;
- }
-
- sub_v3_v3v3(temp, verts[i].tx, verts[j].tx);
-
- if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue;
-
- if (BLI_edgeset_haskey(cloth->edgeset, i, j)) {
- continue;
- }
-
- length = normalize_v3(temp );
-
- if ( length < mindistance ) {
- float correction = mindistance - length;
-
- if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
- mul_v3_fl(temp, -correction);
- VECADD ( verts[j].tx, verts[j].tx, temp );
- }
- else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) {
- mul_v3_fl(temp, correction);
- VECADD ( verts[i].tx, verts[i].tx, temp );
- }
- else {
- mul_v3_fl(temp, correction * -0.5f);
- VECADD ( verts[j].tx, verts[j].tx, temp );
-
- sub_v3_v3v3(verts[i].tx, verts[i].tx, temp);
- }
- ret = 1;
- ret2 += ret;
- }
- else {
- // check for approximated time collisions
- }
- }
-
- if ( overlap )
- MEM_freeN ( overlap );
- }
- }
- ////////////////////////////////////////////////////////////
-
- ////////////////////////////////////////////////////////////
- // SELFCOLLISIONS: update velocities
- ////////////////////////////////////////////////////////////
- if (ret2) {
- for (i = 0; i < cloth->mvert_num; i++) {
- if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) {
- sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
+ /* Apply all collision resolution. */
+ if (ret2) {
+ for (i = 0; i < mvert_num; i++) {
+ if (clmd->sim_parms->vgroup_mass > 0) {
+ if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
+ continue;
}
}
+
+ VECADD(verts[i].tx, verts[i].txold, verts[i].tv);
}
- ////////////////////////////////////////////////////////////
}
+
+ rounds++;
}
- while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
+ while (ret2 && (clmd->coll_parms->loop_count > rounds));
- if (collobjs)
- MEM_freeN(collobjs);
+ if (overlap_obj) {
+ for (i = 0; i < numcollobj; i++) {
+ MEM_SAFE_FREE(overlap_obj[i]);
+ }
- return 1|MIN2 ( ret, 1 );
+ MEM_freeN(overlap_obj);
+ }
+
+ MEM_SAFE_FREE(coll_counts_obj);
+
+ MEM_SAFE_FREE(overlap_self);
+
+ BKE_collision_objects_free(collobjs);
+
+ return MIN2(ret, 1);
}
BLI_INLINE void max_v3_v3v3(float r[3], const float a[3], const float b[3])
@@ -913,106 +1349,6 @@ void collision_get_collider_velocity(float vel_old[3], float vel_new[3], Collisi
copy_v3_v3(vel_old, vel_new);
}
-static bool cloth_points_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd,
- CollPair *collpair, CollPair *collision_end, float dt)
-{
- bool result = false;
- float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - pd->pdef_sbdamp);
- float inv_dt = 1.0f / dt;
- Cloth *cloth1 = clmd->clothObject;
-
- // float w1, w2;
- float u1, u2, u3;
- float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
- float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
-
- for ( ; collpair != collision_end; collpair++ ) {
- float margin_distance = (float)(collpair->distance - (double)epsilon2);
- float impulse[3];
- float mag_v_rel;
-
- if (margin_distance > 0.0f)
- continue;
-
- zero_v3(impulse);
-
- /* only handle static collisions here */
- if ( collpair->flag & COLLISION_IN_FUTURE )
- continue;
-
- /* compute barycentric coordinates for both collision points */
- // w1 = 1.0f - collpair->time;
- // w2 = collpair->time;
-
- /* was: txold */
- collision_compute_barycentric ( collpair->pb,
- collmd->current_x[collpair->bp1].co,
- collmd->current_x[collpair->bp2].co,
- collmd->current_x[collpair->bp3].co,
- &u1, &u2, &u3 );
-
- /* Calculate relative velocity */
- copy_v3_v3(v1, cloth1->verts[collpair->ap1].tv);
-
- collision_interpolateOnTriangle ( v2_new, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
- /* XXX assume constant velocity of the collider for now */
- copy_v3_v3(v2_old, v2_new);
-
- sub_v3_v3v3(v_rel_old, v1, v2_old);
- sub_v3_v3v3(v_rel_new, v1, v2_new);
-
- /* normal component of the relative velocity */
- mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
-
- /**** DEBUG ****/
- BKE_sim_debug_data_add_dot(collpair->pa, 0.9, 0.2, 0.2, "collision", 833, collpair->face1, collpair->face2);
- BKE_sim_debug_data_add_dot(collpair->pb, 0.2, 0.9, 0.2, "collision", 834, collpair->face1, collpair->face2);
- BKE_sim_debug_data_add_line(collpair->pa, collpair->pb, 0.8, 0.8, 0.8, "collision", 835, collpair->face1, collpair->face2);
- /********/
-
- if (mag_v_rel < -ALMOST_ZERO) {
- float v_nor_old, v_nor_new;
- float v_tan_old[3], v_tan_new[3];
- float bounce, repulse;
-
- /* Collision response based on
- * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
- * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
- */
-
- v_nor_old = mag_v_rel;
- v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
-
- madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
- madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
-
- repulse = -margin_distance * inv_dt + dot_v3v3(v1, collpair->normal);
-
- if (margin_distance < -epsilon2) {
- bounce = -v_nor_new + v_nor_old * restitution;
- mul_v3_v3fl(impulse, collpair->normal, max_ff(repulse, bounce));
- }
- else {
- bounce = 0.0f;
- mul_v3_v3fl(impulse, collpair->normal, repulse);
- }
- cloth1->verts[collpair->ap1].impulse_count++;
-
- result = true;
- }
-
- if (result) {
- int i = 0;
-
- for (i = 0; i < 3; i++) {
- if (cloth1->verts[collpair->ap1].impulse_count > 0 && fabsf(cloth1->verts[collpair->ap1].impulse[i]) < fabsf(impulse[i]))
- cloth1->verts[collpair->ap1].impulse[i] = impulse[i];
- }
- }
- }
- return result;
-}
-
BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3],
float r_nor[3], float *r_lambda, float r_w[3])
{
@@ -1024,58 +1360,16 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float
cross_v3_v3v3(r_nor, edge1, edge2);
normalize_v3(r_nor);
+ sub_v3_v3v3(v0p2, p2, v0);
nor_v0p2 = dot_v3v3(v0p2, r_nor);
madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
interp_weights_tri_v3(r_w, v0, v1, v2, p2face);
sub_v3_v3v3(p1p2, p2, p1);
- sub_v3_v3v3(v0p2, p2, v0);
nor_p1p2 = dot_v3v3(p1p2, r_nor);
*r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f);
return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f;
-
-#if 0 /* XXX this method uses the intersection point, but is broken and doesn't work well in general */
- float p[3], vec1[3], line[3], edge1[3], edge2[3], q[3];
- float a, f, u, v;
-
- sub_v3_v3v3(edge1, v1, v0);
- sub_v3_v3v3(edge2, v2, v0);
- sub_v3_v3v3(line, p2, p1);
-
- cross_v3_v3v3(p, line, edge2);
- a = dot_v3v3(edge1, p);
- if (a == 0.0f) return 0;
- f = 1.0f / a;
-
- sub_v3_v3v3(vec1, p1, v0);
-
- u = f * dot_v3v3(vec1, p);
- if ((u < 0.0f) || (u > 1.0f))
- return false;
-
- cross_v3_v3v3(q, vec1, edge1);
-
- v = f * dot_v3v3(line, q);
- if ((v < 0.0f) || ((u + v) > 1.0f))
- return false;
-
- *r_lambda = f * dot_v3v3(edge2, q);
- /* don't care about 0..1 lambda range here */
- /*if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f))
- * return 0;
- */
-
- r_w[0] = 1.0f - u - v;
- r_w[1] = u;
- r_w[2] = v;
- r_w[3] = 0.0f;
-
- cross_v3_v3v3(r_nor, edge1, edge2);
- normalize_v3(r_nor);
-
- return true;
-#endif
}
static CollPair *cloth_point_collpair(
@@ -1164,162 +1458,7 @@ static void cloth_points_objcollisions_nearcheck(
}
}
-static int cloth_points_objcollisions_resolve(
- ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd,
- CollPair *collisions, CollPair *collisions_index, float dt)
-{
- Cloth *cloth = clmd->clothObject;
- int i = 0, mvert_num = clmd->clothObject->mvert_num;
- ClothVertex *verts = cloth->verts;
- int ret = 0;
-
- // process all collisions
- if ( collmd->bvhtree ) {
- bool result = cloth_points_collision_response_static(clmd, collmd, pd, collisions, collisions_index, dt);
-
- // apply impulses in parallel
- if (result) {
- for (i = 0; i < mvert_num; i++) {
- // calculate "velocities" (just xnew = xold + v; no dt in v)
- if (verts[i].impulse_count) {
- // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
- VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
- zero_v3(verts[i].impulse);
- verts[i].impulse_count = 0;
-
- ret++;
- }
- }
- }
- }
-
- return ret;
-}
-
-// cloth - object collisions
-int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt)
-{
- Cloth *cloth= clmd->clothObject;
- BVHTree *cloth_bvh;
- int rounds = 0; // result counts applied collisions; ic is for debug output;
- float round_dt = dt / (float)clmd->coll_parms->loop_count;
- unsigned int i = 0, mvert_num = 0;
- ClothVertex *verts = NULL;
- int ret = 0, ret2 = 0;
- Object **collobjs = NULL;
- unsigned int numcollobj = 0;
-
- verts = cloth->verts;
- mvert_num = cloth->mvert_num;
-
- ////////////////////////////////////////////////////////////
- // static collisions
- ////////////////////////////////////////////////////////////
-
- // create temporary cloth points bvh
- cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
- /* fill tree */
- for (i = 0; i < mvert_num; i++) {
- float co[2][3];
-
- copy_v3_v3(co[0], verts[i].x);
- copy_v3_v3(co[1], verts[i].tx);
-
- BLI_bvhtree_insert(cloth_bvh, i, co[0], 2);
- }
- /* balance tree */
- BLI_bvhtree_balance(cloth_bvh);
-
- collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
- if (!collobjs)
- return 0;
-
- /* move object to position (step) in time */
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- if (!collmd->bvhtree)
- continue;
-
- /* move object to position (step) in time */
- collision_move_object ( collmd, step + dt, step );
- }
-
- do {
- CollPair **collisions, **collisions_index;
-
- ret2 = 0;
-
- collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
- collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
-
- // check all collision objects
- for (i = 0; i < numcollobj; i++) {
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
- BVHTreeOverlap *overlap = NULL;
- unsigned int result = 0;
- float epsilon;
-
- if (!collmd->bvhtree)
- continue;
-
- /* search for overlapping collision pairs */
- overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
- epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
-
- // go to next object if no overlap is there
- if (result && overlap) {
- /* check if collisions really happen (costly near check) */
- cloth_points_objcollisions_nearcheck(clmd, collmd, &collisions[i], &collisions_index[i],
- result, overlap, epsilon, round_dt);
-
- // resolve nearby collisions
- ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], round_dt);
- ret2 += ret;
- }
-
- if (overlap)
- MEM_freeN ( overlap );
- }
- rounds++;
-
- for (i = 0; i < numcollobj; i++) {
- if (collisions[i])
- MEM_freeN(collisions[i]);
- }
-
- MEM_freeN(collisions);
- MEM_freeN(collisions_index);
-
- ////////////////////////////////////////////////////////////
- // update positions
- // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
- ////////////////////////////////////////////////////////////
-
- // verts come from clmd
- for (i = 0; i < mvert_num; i++) {
- if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
- if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
- continue;
- }
- }
-
- VECADD ( verts[i].tx, verts[i].txold, verts[i].tv );
- }
- ////////////////////////////////////////////////////////////
- }
- while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
-
- if (collobjs)
- MEM_freeN(collobjs);
-
- BLI_bvhtree_free(cloth_bvh);
-
- return 1|MIN2 ( ret, 1 );
-}
-
-void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, float dt,
+void cloth_find_point_contacts(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt,
ColliderContacts **r_collider_contacts, int *r_totcolliders)
{
Cloth *cloth= clmd->clothObject;
@@ -1340,7 +1479,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
////////////////////////////////////////////////////////////
/* Check we do have collision objects to test against, before doing anything else. */
- collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
if (!collobjs) {
*r_collider_contacts = NULL;
*r_totcolliders = 0;
@@ -1348,7 +1487,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
}
// create temporary cloth points bvh
- cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
+ cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6);
/* fill tree */
for (i = 0; i < mvert_num; i++) {
float co[6];
@@ -1412,8 +1551,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
MEM_freeN(overlap);
}
- if (collobjs)
- MEM_freeN(collobjs);
+ BKE_collision_objects_free(collobjs);
BLI_bvhtree_free(cloth_bvh);
@@ -1424,7 +1562,7 @@ void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step,
// verts come from clmd
for (i = 0; i < mvert_num; i++) {
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
+ if (clmd->sim_parms->vgroup_mass > 0) {
if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
continue;
}
diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c
index f72d4df725a..38631c76009 100644
--- a/source/blender/blenkernel/intern/colorband.c
+++ b/source/blender/blenkernel/intern/colorband.c
@@ -208,7 +208,7 @@ static void colorband_init_from_table_rgba_resample(
}
while ((carr_len > 1 && !BLI_heap_is_empty(heap)) &&
- ((carr_len >= MAXCOLORBAND) || (BLI_heap_node_value(BLI_heap_top(heap)) <= eps_2x)))
+ ((carr_len >= MAXCOLORBAND) || (BLI_heap_top_value(heap) <= eps_2x)))
{
c = BLI_heap_pop_min(heap);
struct ColorResampleElem *c_next = c->next, *c_prev = c->prev;
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index ff4795afe87..108e188fe92 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -282,6 +282,7 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
case CURVE_PRESET_MID9: cuma->totpoint = 9; break;
case CURVE_PRESET_ROUND: cuma->totpoint = 4; break;
case CURVE_PRESET_ROOT: cuma->totpoint = 4; break;
+ case CURVE_PRESET_GAUSS: cuma->totpoint = 7; break;
}
cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points");
@@ -352,6 +353,24 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
cuma->curve[3].x = 1;
cuma->curve[3].y = 0;
break;
+ case CURVE_PRESET_GAUSS:
+ cuma->curve[0].x = 0;
+ cuma->curve[0].y = 0.025f;
+ cuma->curve[1].x = 0.16f;
+ cuma->curve[1].y = 0.135f;
+ cuma->curve[2].x = 0.298f;
+ cuma->curve[2].y = 0.36f;
+
+ cuma->curve[3].x = 0.50f;
+ cuma->curve[3].y = 1.0f;
+
+ cuma->curve[4].x = 0.70f;
+ cuma->curve[4].y = 0.36f;
+ cuma->curve[5].x = 0.84f;
+ cuma->curve[5].y = 0.135f;
+ cuma->curve[6].x = 1.0f;
+ cuma->curve[6].y = 0.025f;
+ break;
}
/* mirror curve in x direction to have positive slope
@@ -919,6 +938,22 @@ void curvemapping_evaluateRGBF(const CurveMapping *cumap, float vecout[3], const
vecout[2] = curvemap_evaluateF(&cumap->cm[2], curvemap_evaluateF(&cumap->cm[3], vecin[2]));
}
+static void curvemapping_evaluateRGBF_filmlike(const CurveMapping *cumap, float vecout[3], const float vecin[3],
+ const int channel_offset[3])
+{
+ const float v0in = vecin[channel_offset[0]];
+ const float v1in = vecin[channel_offset[1]];
+ const float v2in = vecin[channel_offset[2]];
+
+ const float v0 = curvemap_evaluateF(&cumap->cm[channel_offset[0]], v0in);
+ const float v2 = curvemap_evaluateF(&cumap->cm[channel_offset[2]], v2in);
+ const float v1 = v2 + ((v0 - v2) * (v1in - v2in) / (v0in - v2in));
+
+ vecout[channel_offset[0]] = v0;
+ vecout[channel_offset[1]] = v1;
+ vecout[channel_offset[2]] = v2;
+}
+
/** same as #curvemapping_evaluate_premulRGBF
* but black/bwmul are passed as args for the compositor
* where they can change per pixel.
@@ -928,20 +963,73 @@ void curvemapping_evaluateRGBF(const CurveMapping *cumap, float vecout[3], const
* \param black Use instead of cumap->black
* \param bwmul Use instead of cumap->bwmul
*/
-void curvemapping_evaluate_premulRGBF_ex(const CurveMapping *cumap, float vecout[3], const float vecin[3],
- const float black[3], const float bwmul[3])
+void curvemapping_evaluate_premulRGBF_ex(
+ const CurveMapping *cumap, float vecout[3], const float vecin[3],
+ const float black[3], const float bwmul[3])
{
- vecout[0] = curvemap_evaluateF(&cumap->cm[0], (vecin[0] - black[0]) * bwmul[0]);
- vecout[1] = curvemap_evaluateF(&cumap->cm[1], (vecin[1] - black[1]) * bwmul[1]);
- vecout[2] = curvemap_evaluateF(&cumap->cm[2], (vecin[2] - black[2]) * bwmul[2]);
+ const float r = (vecin[0] - black[0]) * bwmul[0];
+ const float g = (vecin[1] - black[1]) * bwmul[1];
+ const float b = (vecin[2] - black[2]) * bwmul[2];
+
+ switch (cumap->tone) {
+ default:
+ case CURVE_TONE_STANDARD:
+ {
+ vecout[0] = curvemap_evaluateF(&cumap->cm[0], r);
+ vecout[1] = curvemap_evaluateF(&cumap->cm[1], g);
+ vecout[2] = curvemap_evaluateF(&cumap->cm[2], b);
+ break;
+ }
+ case CURVE_TONE_FILMLIKE:
+ {
+ if (r >= g) {
+ if (g > b) {
+ /* Case 1: r >= g > b */
+ const int shuffeled_channels[] = {0, 1, 2};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else if (b > r) {
+ /* Case 2: b > r >= g */
+ const int shuffeled_channels[] = {2, 0, 1};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else if (b > g) {
+ /* Case 3: r >= b > g */
+ const int shuffeled_channels[] = {0, 2, 1};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else {
+ /* Case 4: r >= g == b */
+ copy_v2_fl2(vecout, curvemap_evaluateF(&cumap->cm[0], r), curvemap_evaluateF(&cumap->cm[1], g));
+ vecout[2] = vecout[1];
+ }
+ }
+ else {
+ if (r >= b) {
+ /* Case 5: g > r >= b */
+ const int shuffeled_channels[] = {1, 0, 2};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else if (b > g) {
+ /* Case 6: b > g > r */
+ const int shuffeled_channels[] = {2, 1, 0};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ else {
+ /* Case 7: g >= b > r */
+ const int shuffeled_channels[] = {1, 2, 0};
+ curvemapping_evaluateRGBF_filmlike(cumap, vecout, vecin, shuffeled_channels);
+ }
+ }
+ break;
+ }
+ }
}
/* RGB with black/white points and premult. tables are checked */
void curvemapping_evaluate_premulRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
{
- vecout[0] = curvemap_evaluateF(&cumap->cm[0], (vecin[0] - cumap->black[0]) * cumap->bwmul[0]);
- vecout[1] = curvemap_evaluateF(&cumap->cm[1], (vecin[1] - cumap->black[1]) * cumap->bwmul[1]);
- vecout[2] = curvemap_evaluateF(&cumap->cm[2], (vecin[2] - cumap->black[2]) * cumap->bwmul[2]);
+ curvemapping_evaluate_premulRGBF_ex(cumap, vecout, vecin, cumap->black, cumap->bwmul);
}
/* same as above, byte version */
@@ -1401,17 +1489,6 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
scopes_update_cb,
&settings);
- /* test for nicer distribution even - non standard, leave it out for a while */
-#if 0
- for (a = 0; a < 256; a++) {
- bin_lum[a] = sqrt (bin_lum[a]);
- bin_r[a] = sqrt(bin_r[a]);
- bin_g[a] = sqrt(bin_g[a]);
- bin_b[a] = sqrt(bin_b[a]);
- bin_a[a] = sqrt(bin_a[a]);
- }
-#endif
-
/* convert hist data to float (proportional to max count) */
nl = na = nr = nb = ng = 0;
for (a = 0; a < 256; a++) {
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 2f3a18cd163..dccc959b4ea 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -52,6 +52,7 @@
#include "DNA_object_types.h"
#include "DNA_action_types.h"
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_lattice_types.h"
@@ -68,22 +69,24 @@
#include "BKE_camera.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
-#include "BKE_displist.h"
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h" /* for geometry targets */
-#include "BKE_cdderivedmesh.h" /* for geometry targets */
-#include "BKE_object.h"
+#include "BKE_displist.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
-#include "BKE_library.h"
#include "BKE_idprop.h"
-#include "BKE_shrinkwrap.h"
-#include "BKE_editmesh.h"
+#include "BKE_library.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_movieclip.h"
+#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BKE_shrinkwrap.h"
#include "BKE_tracking.h"
-#include "BKE_movieclip.h"
#include "BIK_api.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#ifdef WITH_PYTHON
# include "BPY_extern.h"
#endif
@@ -98,17 +101,14 @@
/* Constraint Target Macros */
#define VALID_CONS_TARGET(ct) ((ct) && (ct->tar))
-/* Workaround for cyclic depenndnecy with curves.
- * In such case curve_cache might not be ready yet,
- */
-#define CYCLIC_DEPENDENCY_WORKAROUND
-
/* ************************ Constraints - General Utilities *************************** */
/* These functions here don't act on any specific constraints, and are therefore should/will
* not require any of the special function-pointers afforded by the relevant constraint
* type-info structs.
*/
+static void damptrack_do_transform(float matrix[4][4], const float tarvec[3], int track_axis);
+
/* -------------- Naming -------------- */
/* Find the first available, non-duplicate name for a given constraint */
@@ -121,7 +121,7 @@ void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
/* package an object/bone for use in constraint evaluation */
/* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */
-bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subdata, short datatype)
+bConstraintOb *BKE_constraints_make_evalob(Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
{
bConstraintOb *cob;
@@ -130,6 +130,7 @@ bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subda
/* for system time, part of deglobalization, code nicer later with local time (ton) */
cob->scene = scene;
+ cob->depsgraph = depsgraph;
/* based on type of available data */
switch (datatype) {
@@ -392,99 +393,104 @@ void BKE_constraint_mat_convertspace(
/* function that sets the given matrix based on given vertex group in mesh */
static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[4][4])
{
- DerivedMesh *dm = NULL;
+ /* when not in EditMode, use the 'final' evaluated mesh, depsgraph
+ * ensures we build with CD_MDEFORMVERT layer
+ */
+ Mesh *me_eval = ob->runtime.mesh_eval;
BMEditMesh *em = BKE_editmesh_from_object(ob);
- float vec[3] = {0.0f, 0.0f, 0.0f};
- float normal[3] = {0.0f, 0.0f, 0.0f}, plane[3];
+ float plane[3];
float imat[3][3], tmat[3][3];
const int defgroup = defgroup_name_index(ob, substring);
- short freeDM = 0;
/* initialize target matrix using target matrix */
copy_m4_m4(mat, ob->obmat);
/* get index of vertex group */
- if (defgroup == -1) return;
-
- /* get DerivedMesh */
- if (em) {
- /* target is in editmode, so get a special derived mesh */
- dm = CDDM_from_editbmesh(em, false, false);
- freeDM = 1;
- }
- else {
- /* when not in EditMode, use the 'final' derived mesh, depsgraph
- * ensures we build with CD_MDEFORMVERT layer
- */
- dm = (DerivedMesh *)ob->derivedFinal;
+ if (defgroup == -1) {
+ return;
}
- /* only continue if there's a valid DerivedMesh */
- if (dm) {
- MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
- int numVerts = dm->getNumVerts(dm);
- int i;
- float co[3], nor[3];
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ float normal[3] = {0.0f, 0.0f, 0.0f};
+ float weightsum = 0.0f;
+ if (me_eval) {
+ MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT);
+ int numVerts = me_eval->totvert;
/* check that dvert is a valid pointers (just in case) */
if (dvert) {
MDeformVert *dv = dvert;
- float weightsum = 0.0f;
+ MVert *mv = me_eval->mvert;
/* get the average of all verts with that are in the vertex-group */
- for (i = 0; i < numVerts; i++, dv++) {
+ for (int i = 0; i < numVerts; i++, dv++, mv++) {
MDeformWeight *dw = defvert_find_index(dv, defgroup);
if (dw && dw->weight > 0.0f) {
- dm->getVertCo(dm, i, co);
- dm->getVertNo(dm, i, nor);
- madd_v3_v3fl(vec, co, dw->weight);
+ float nor[3];
+ normal_short_to_float_v3(nor, mv->no);
+ madd_v3_v3fl(vec, mv->co, dw->weight);
madd_v3_v3fl(normal, nor, dw->weight);
weightsum += dw->weight;
}
}
+ }
+ }
+ else if (em) {
+ if (CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) {
+ BMVert *v;
+ BMIter iter;
- /* calculate averages of normal and coordinates */
- if (weightsum > 0) {
- mul_v3_fl(vec, 1.0f / weightsum);
- mul_v3_fl(normal, 1.0f / weightsum);
- }
-
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ MDeformVert *dv = CustomData_bmesh_get(&em->bm->vdata, v->head.data, CD_MDEFORMVERT);
+ MDeformWeight *dw = defvert_find_index(dv, defgroup);
- /* derive the rotation from the average normal:
- * - code taken from transform_manipulator.c,
- * calc_manipulator_stats, V3D_MANIP_NORMAL case
- */
- /* we need the transpose of the inverse for a normal... */
- copy_m3_m4(imat, ob->obmat);
+ if (dw && dw->weight > 0.0f) {
+ madd_v3_v3fl(vec, v->co, dw->weight);
+ madd_v3_v3fl(normal, v->no, dw->weight);
+ weightsum += dw->weight;
+ }
+ }
+ }
+ }
+ else {
+ /* No valid edit or evaluated mesh, just abort. */
+ return;
+ }
- invert_m3_m3(tmat, imat);
- transpose_m3(tmat);
- mul_m3_v3(tmat, normal);
+ /* calculate averages of normal and coordinates */
+ if (weightsum > 0) {
+ mul_v3_fl(vec, 1.0f / weightsum);
+ mul_v3_fl(normal, 1.0f / weightsum);
+ }
- normalize_v3(normal);
- copy_v3_v3(plane, tmat[1]);
+ /* derive the rotation from the average normal:
+ * - code taken from transform_gizmo.c,
+ * calc_gizmo_stats, V3D_MANIP_NORMAL case
+ */
+ /* we need the transpose of the inverse for a normal... */
+ copy_m3_m4(imat, ob->obmat);
- cross_v3_v3v3(mat[0], normal, plane);
- if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) {
- copy_v3_v3(plane, tmat[0]);
- cross_v3_v3v3(mat[0], normal, plane);
- }
+ invert_m3_m3(tmat, imat);
+ transpose_m3(tmat);
+ mul_m3_v3(tmat, normal);
- copy_v3_v3(mat[2], normal);
- cross_v3_v3v3(mat[1], mat[2], mat[0]);
+ normalize_v3(normal);
+ copy_v3_v3(plane, tmat[1]);
- normalize_m4(mat);
+ cross_v3_v3v3(mat[0], normal, plane);
+ if (len_squared_v3(mat[0]) < SQUARE(1e-3f)) {
+ copy_v3_v3(plane, tmat[0]);
+ cross_v3_v3v3(mat[0], normal, plane);
+ }
+ copy_v3_v3(mat[2], normal);
+ cross_v3_v3v3(mat[1], mat[2], mat[0]);
- /* apply the average coordinate as the new location */
- mul_v3_m4v3(mat[3], ob->obmat, vec);
- }
- }
+ normalize_m4(mat);
- /* free temporary DerivedMesh created (in EditMode case) */
- if (dm && freeDM)
- dm->release(dm);
+ /* apply the average coordinate as the new location */
+ mul_v3_m4v3(mat[3], ob->obmat, vec);
}
/* function that sets the given matrix based on given vertex group in lattice */
@@ -492,7 +498,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
{
Lattice *lt = (Lattice *)ob->data;
- DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL;
const float *co = dl ? dl->verts : NULL;
BPoint *bp = lt->def;
@@ -575,18 +581,21 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
* PoseChannel by the Armature Object's Matrix to get a worldspace
* matrix.
*/
- if (headtail < 0.000001f) {
+ bool is_bbone = (pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE);
+ bool full_bbone = (flag & CONSTRAINT_BBONE_SHAPE_FULL) != 0;
+
+ if (headtail < 0.000001f && !(is_bbone && full_bbone)) {
/* skip length interpolation if set to head */
mul_m4_m4m4(mat, ob->obmat, pchan->pose_mat);
}
- else if ((pchan->bone) && (pchan->bone->segments > 1) && (flag & CONSTRAINT_BBONE_SHAPE)) {
+ else if (is_bbone) {
/* use point along bbone */
Mat4 bbone[MAX_BBONE_SUBDIV];
float tempmat[4][4];
float loc[3], fac;
/* get bbone segments */
- b_bone_spline_setup(pchan, 0, bbone);
+ b_bone_spline_setup(pchan, false, bbone);
/* figure out which segment(s) the headtail value falls in */
fac = (float)pchan->bone->segments * headtail;
@@ -625,8 +634,18 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m
mul_v3_m4v3(loc, pchan->pose_mat, pt);
}
+ /* apply full transformation of the segment if requested */
+ if (full_bbone) {
+ int index = floorf(fac);
+ CLAMP(index, 0, pchan->bone->segments - 1);
+
+ mul_m4_m4m4(tempmat, pchan->pose_mat, bbone[index].mat);
+ }
+ else {
+ copy_m4_m4(tempmat, pchan->pose_mat);
+ }
+
/* use interpolated distance for subtarget */
- copy_m4_m4(tempmat, pchan->pose_mat);
copy_v3_v3(tempmat[3], loc);
mul_m4_m4m4(mat, ob->obmat, tempmat);
@@ -689,7 +708,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
/* This function should be used for the get_target_matrix member of all
* constraints that are not picky about what happens to their target matrix.
*/
-static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
+static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
{
if (VALID_CONS_TARGET(ct))
constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag, con->headtail);
@@ -697,6 +716,16 @@ static void default_get_tarmat(bConstraint *con, bConstraintOb *UNUSED(cob), bCo
unit_m4(ct->matrix);
}
+/* This is a variant that extracts full transformation from B-Bone segments.
+ */
+static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *UNUSED(cob), bConstraintTarget *ct, float UNUSED(ctime))
+{
+ if (VALID_CONS_TARGET(ct))
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space, con->flag | CONSTRAINT_BBONE_SHAPE_FULL, con->headtail);
+ else if (ct)
+ unit_m4(ct->matrix);
+}
+
/* This following macro should be used for all standard single-target *_get_tars functions
* to save typing and reduce maintenance woes.
* (Hopefully all compilers will be happy with the lines with just a space on them. Those are
@@ -1158,7 +1187,7 @@ static void kinematic_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void kinematic_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
{
bKinematicConstraint *data = con->data;
@@ -1245,7 +1274,9 @@ static void followpath_flush_tars(bConstraint *con, ListBase *list, bool no_copy
}
}
-static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con, bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
bFollowPathConstraint *data = con->data;
@@ -1260,13 +1291,7 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
* currently for paths to work it needs to go through the bevlist/displist system (ton)
*/
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
-#endif
-
- if (ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) {
+ if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path && ct->tar->runtime.curve_cache->path->data) {
float quat[4];
if ((data->followflag & FOLLOWPATH_STATIC) == 0) {
/* animated position along curve depending on time */
@@ -1303,21 +1328,7 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
unit_m4(totmat);
if (data->followflag & FOLLOWPATH_FOLLOW) {
-#if 0
- float x1, q[4];
- vec_to_quat(quat, dir, (short)data->trackflag, (short)data->upflag);
-
- normalize_v3(dir);
- q[0] = cosf(0.5 * vec[3]);
- x1 = sinf(0.5 * vec[3]);
- q[1] = -x1 * dir[0];
- q[2] = -x1 * dir[1];
- q[3] = -x1 * dir[2];
- mul_qt_qtqt(quat, q, quat);
-#else
quat_apply_track(quat, data->trackflag, data->upflag);
-#endif
-
quat_to_mat4(totmat, quat);
}
@@ -1760,7 +1771,7 @@ static void sizelike_new_data(void *cdata)
{
bSizeLikeConstraint *data = (bSizeLikeConstraint *)cdata;
- data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z;
+ data->flag = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z | SIZELIKE_MULTIPLY;
}
static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -1808,29 +1819,28 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta
mat4_to_size(size, ct->matrix);
mat4_to_size(obsize, cob->matrix);
- if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) {
- if (data->flag & SIZELIKE_OFFSET) {
- size[0] += (obsize[0] - 1.0f);
- mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
+ if (data->flag & SIZELIKE_OFFSET) {
+ /* Scale is a multiplicative quantity, so adding it makes no sense.
+ * However, the additive mode has to stay for backward compatibility. */
+ if (data->flag & SIZELIKE_MULTIPLY) {
+ /* size[i] *= obsize[i] */
+ mul_v3_v3(size, obsize);
+ }
+ else {
+ /* 2.7 compatibility mode: size[i] += (obsize[i] - 1.0f) */
+ add_v3_v3(size, obsize);
+ add_v3_fl(size, -1.0f);
}
- else
- mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
+ }
+
+ if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) {
+ mul_v3_fl(cob->matrix[0], size[0] / obsize[0]);
}
if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) {
- if (data->flag & SIZELIKE_OFFSET) {
- size[1] += (obsize[1] - 1.0f);
- mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
- }
- else
- mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
+ mul_v3_fl(cob->matrix[1], size[1] / obsize[1]);
}
if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) {
- if (data->flag & SIZELIKE_OFFSET) {
- size[2] += (obsize[2] - 1.0f);
- mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
- }
- else
- mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
+ mul_v3_fl(cob->matrix[2], size[2] / obsize[2]);
}
}
}
@@ -1907,7 +1917,7 @@ static bConstraintTypeInfo CTI_TRANSLIKE = {
NULL, /* new data */
translike_get_tars, /* get constraint targets */
translike_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
+ default_get_tarmat_full_bbone, /* get target matrix */
translike_evaluate /* evaluate */
};
@@ -2028,21 +2038,19 @@ static void pycon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userd
}
/* Whether this approach is maintained remains to be seen (aligorith) */
-static void pycon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *con, bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
#ifdef WITH_PYTHON
bPythonConstraint *data = con->data;
#endif
if (VALID_CONS_TARGET(ct)) {
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- /* special exception for curves - depsgraph issues */
- if (ct->tar->type == OB_CURVE) {
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
+ if (ct->tar->type == OB_CURVE && ct->tar->runtime.curve_cache == NULL) {
+ unit_m4(ct->matrix);
+ return;
}
-#endif
/* firstly calculate the matrix the normal way, then let the py-function override
* this matrix if it needs to do so
@@ -2070,15 +2078,6 @@ static void pycon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targe
/* only evaluate in python if we're allowed to do so */
if ((G.f & G_SCRIPT_AUTOEXEC) == 0) return;
-/* currently removed, until I this can be re-implemented for multiple targets */
-#if 0
- /* Firstly, run the 'driver' function which has direct access to the objects involved
- * Technically, this is potentially dangerous as users may abuse this and cause dependency-problems,
- * but it also allows certain 'clever' rigging hacks to work.
- */
- BPY_pyconstraint_driver(data, cob, targets);
-#endif
-
/* Now, run the actual 'constraint' function, which should only access the matrices */
BPY_pyconstraint_exec(data, cob, targets);
#endif /* WITH_PYTHON */
@@ -2099,6 +2098,206 @@ static bConstraintTypeInfo CTI_PYTHON = {
pycon_evaluate /* evaluate */
};
+/* ----------- Armature Constraint -------------- */
+
+static void armdef_free(bConstraint *con)
+{
+ bArmatureConstraint *data = con->data;
+
+ /* Target list. */
+ BLI_freelistN(&data->targets);
+}
+
+static void armdef_copy(bConstraint *con, bConstraint *srccon)
+{
+ bArmatureConstraint *pcon = (bArmatureConstraint *)con->data;
+ bArmatureConstraint *opcon = (bArmatureConstraint *)srccon->data;
+
+ BLI_duplicatelist(&pcon->targets, &opcon->targets);
+}
+
+static int armdef_get_tars(bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bArmatureConstraint *data = con->data;
+
+ *list = data->targets;
+
+ return BLI_listbase_count(&data->targets);
+ }
+
+ return 0;
+}
+
+static void armdef_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
+{
+ bArmatureConstraint *data = con->data;
+ bConstraintTarget *ct;
+
+ /* Target list. */
+ for (ct = data->targets.first; ct; ct = ct->next) {
+ func(con, (ID **)&ct->tar, false, userdata);
+ }
+}
+
+/* Compute the world space pose matrix of the target bone. */
+static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
+{
+ if (ct != NULL) {
+ if (ct->tar && ct->tar->type == OB_ARMATURE) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget);
+
+ if (pchan != NULL) {
+ mul_m4_m4m4(ct->matrix, ct->tar->obmat, pchan->pose_mat);
+ return;
+ }
+ }
+
+ unit_m4(ct->matrix);
+ }
+}
+
+/* Compute and accumulate transformation for a single target bone. */
+static void armdef_accumulate_bone(bConstraintTarget *ct, bPoseChannel *pchan, const float wco[3], bool force_envelope, float *r_totweight, float r_sum_mat[4][4], DualQuat *r_sum_dq)
+{
+ float mat[4][4], iobmat[4][4], iamat[4][4], basemat[4][4], co[3];
+ Bone *bone = pchan->bone;
+ float weight = ct->weight;
+
+ /* Our object's location in target pose space. */
+ invert_m4_m4(iobmat, ct->tar->obmat);
+ mul_v3_m4v3(co, iobmat, wco);
+
+ /* Inverted rest pose matrix: bone->chan_mat may not be final yet. */
+ invert_m4_m4(iamat, bone->arm_mat);
+
+ /* Multiply by the envelope weight when appropriate. */
+ if (force_envelope || (bone->flag & BONE_MULT_VG_ENV)) {
+ weight *= distfactor_to_bone(co, bone->arm_head, bone->arm_tail,
+ bone->rad_head, bone->rad_tail, bone->dist);
+ }
+
+ /* Find the correct bone transform matrix in world space. */
+ if (bone->segments > 1) {
+ /* The target is a B-Bone:
+ * FIRST: find the segment (see b_bone_deform in armature.c)
+ * Need to transform co back to bonespace, only need y. */
+ float y = iamat[0][1] * co[0] + iamat[1][1] * co[1] + iamat[2][1] * co[2] + iamat[3][1];
+
+ float segment = bone->length / ((float)bone->segments);
+ int a = (int)(y / segment);
+
+ CLAMP(a, 0, bone->segments - 1);
+
+ /* SECOND: compute the matrix (see pchan_b_bone_defmats in armature.c) */
+ Mat4 b_bone[MAX_BBONE_SUBDIV], b_bone_rest[MAX_BBONE_SUBDIV];
+ float irmat[4][4];
+
+ b_bone_spline_setup(pchan, false, b_bone);
+ b_bone_spline_setup(pchan, true, b_bone_rest);
+
+ invert_m4_m4(irmat, b_bone_rest[a].mat);
+ mul_m4_series(mat, ct->matrix, b_bone[a].mat, irmat, iamat, iobmat);
+ }
+ else {
+ /* Simple bone. */
+ mul_m4_series(mat, ct->matrix, iamat, iobmat);
+ }
+
+ /* Accumulate the transformation. */
+ *r_totweight += weight;
+
+ if (r_sum_dq != NULL) {
+ DualQuat tmpdq;
+
+ mul_m4_series(basemat, ct->tar->obmat, bone->arm_mat, iobmat);
+
+ mat4_to_dquat(&tmpdq, basemat, mat);
+ add_weighted_dq_dq(r_sum_dq, &tmpdq, weight);
+ }
+ else {
+ mul_m4_fl(mat, weight);
+ add_m4_m4m4(r_sum_mat, r_sum_mat, mat);
+ }
+}
+
+static void armdef_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bArmatureConstraint *data = con->data;
+
+ float sum_mat[4][4], input_co[3];
+ DualQuat sum_dq;
+ float weight = 0.0f;
+
+ /* Prepare for blending. */
+ zero_m4(sum_mat);
+ memset(&sum_dq, 0, sizeof(sum_dq));
+
+ DualQuat *pdq = (data->flag & CONSTRAINT_ARMATURE_QUATERNION) ? &sum_dq : NULL;
+ bool use_envelopes = (data->flag & CONSTRAINT_ARMATURE_ENVELOPE) != 0;
+
+ if (cob->pchan && cob->pchan->bone && !(data->flag & CONSTRAINT_ARMATURE_CUR_LOCATION)) {
+ /* For constraints on bones, use the rest position to bind b-bone segments
+ * and envelopes, to allow safely changing the bone location as if parented. */
+ copy_v3_v3(input_co, cob->pchan->bone->arm_head);
+ mul_m4_v3(cob->ob->obmat, input_co);
+ }
+ else {
+ copy_v3_v3(input_co, cob->matrix[3]);
+ }
+
+ /* Process all targets. */
+ for (bConstraintTarget *ct = targets->first; ct; ct = ct->next) {
+ if (ct->weight <= 0.0f) {
+ continue;
+ }
+
+ /* Lookup the bone and abort if failed. */
+ if (!VALID_CONS_TARGET(ct) || ct->tar->type != OB_ARMATURE) {
+ return;
+ }
+
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ct->tar->pose, ct->subtarget);
+
+ if (pchan == NULL || pchan->bone == NULL) {
+ return;
+ }
+
+ armdef_accumulate_bone(ct, pchan, input_co, use_envelopes, &weight, sum_mat, pdq);
+ }
+
+ /* Compute the final transform. */
+ if (weight > 0.0f) {
+ if (pdq != NULL) {
+ normalize_dq(pdq, weight);
+ dquat_to_mat4(sum_mat, pdq);
+ }
+ else {
+ mul_m4_fl(sum_mat, 1.0f / weight);
+ }
+
+ /* Apply the transform to the result matrix. */
+ mul_m4_m4m4(cob->matrix, sum_mat, cob->matrix);
+ }
+}
+
+static bConstraintTypeInfo CTI_ARMATURE = {
+ CONSTRAINT_TYPE_ARMATURE, /* type */
+ sizeof(bArmatureConstraint), /* size */
+ "Armature", /* name */
+ "bArmatureConstraint", /* struct name */
+ armdef_free, /* free data */
+ armdef_id_looper, /* id looper */
+ armdef_copy, /* copy data */
+ NULL, /* new data */
+ armdef_get_tars, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ armdef_get_tarmat, /* get target matrix */
+ armdef_evaluate /* evaluate */
+};
+
/* -------- Action Constraint ----------- */
static void actcon_new_data(void *cdata)
@@ -2146,7 +2345,7 @@ static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void actcon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
{
bActionConstraint *data = con->data;
@@ -3039,66 +3238,6 @@ static bConstraintTypeInfo CTI_MINMAX = {
minmax_evaluate /* evaluate */
};
-/* ------- RigidBody Joint ---------- */
-
-static void rbj_new_data(void *cdata)
-{
- bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)cdata;
-
- /* removed code which set target of this constraint */
- data->type = 1;
-}
-
-static void rbj_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
-{
- bRigidBodyJointConstraint *data = con->data;
-
- /* target only */
- func(con, (ID **)&data->tar, false, userdata);
- func(con, (ID **)&data->child, false, userdata);
-}
-
-static int rbj_get_tars(bConstraint *con, ListBase *list)
-{
- if (con && list) {
- bRigidBodyJointConstraint *data = con->data;
- bConstraintTarget *ct;
-
- /* standard target-getting macro for single-target constraints without subtargets */
- SINGLETARGETNS_GET_TARS(con, data->tar, ct, list);
-
- return 1;
- }
-
- return 0;
-}
-
-static void rbj_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
-{
- if (con && list) {
- bRigidBodyJointConstraint *data = con->data;
- bConstraintTarget *ct = list->first;
-
- /* the following macro is used for all standard single-target constraints */
- SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, no_copy);
- }
-}
-
-static bConstraintTypeInfo CTI_RIGIDBODYJOINT = {
- CONSTRAINT_TYPE_RIGIDBODYJOINT, /* type */
- sizeof(bRigidBodyJointConstraint), /* size */
- "Rigid Body Joint", /* name */
- "bRigidBodyJointConstraint", /* struct name */
- NULL, /* free data */
- rbj_id_looper, /* id looper */
- NULL, /* copy data */
- rbj_new_data, /* new data */
- rbj_get_tars, /* get constraint targets */
- rbj_flush_tars, /* flush constraint targets */
- default_get_tarmat, /* get target matrix */
- NULL /* evaluate - this is not solved here... is just an interface for game-engine */
-};
-
/* -------- Clamp To ---------- */
static void clampto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -3135,16 +3274,10 @@ static void clampto_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void clampto_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void clampto_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (VALID_CONS_TARGET(ct)) {
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
- }
-#endif
-
/* technically, this isn't really needed for evaluation, but we don't know what else
* might end up calling this...
*/
@@ -3172,7 +3305,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
BKE_object_minmax(ct->tar, curveMin, curveMax, true);
/* get targetmatrix */
- if (data->tar->curve_cache && data->tar->curve_cache->path && data->tar->curve_cache->path->data) {
+ if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path && data->tar->runtime.curve_cache->path->data) {
float vec[4], dir[3], totmat[4][4];
float curvetime;
short clamp_axis;
@@ -3478,53 +3611,64 @@ static void shrinkwrap_flush_tars(bConstraint *con, ListBase *list, bool no_copy
}
-static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph), bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
{
bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data;
if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_MESH) ) {
+
bool fail = false;
float co[3] = {0.0f, 0.0f, 0.0f};
+ bool track_normal = false;
+ float track_no[3] = {0.0f, 0.0f, 0.0f};
SpaceTransform transform;
- /* TODO(sergey): use proper for_render flag here when known. */
- DerivedMesh *target = object_get_derived_final(ct->tar, false);
+ Mesh *target_eval = ct->tar->runtime.mesh_eval;
- BVHTreeFromMesh treeData = {NULL};
+ copy_m4_m4(ct->matrix, cob->matrix);
- unit_m4(ct->matrix);
+ bool do_track_normal = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0;
+ ShrinkwrapTreeData tree;
- if (target != NULL) {
+ if (BKE_shrinkwrap_init_tree(&tree, target_eval, scon->shrinkType, scon->shrinkMode, do_track_normal)) {
BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat);
switch (scon->shrinkType) {
case MOD_SHRINKWRAP_NEAREST_SURFACE:
case MOD_SHRINKWRAP_NEAREST_VERTEX:
+ case MOD_SHRINKWRAP_TARGET_PROJECT:
{
BVHTreeNearest nearest;
- float dist;
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
- if (scon->shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX)
- bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_VERTS, 2);
- else
- bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_space_transform_apply(&transform, co);
+
+ BKE_shrinkwrap_find_nearest_surface(&tree, &nearest, co, scon->shrinkType);
- if (treeData.tree == NULL) {
+ if (nearest.index < 0) {
fail = true;
break;
}
- BLI_space_transform_apply(&transform, co);
+ if (scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) {
+ if (do_track_normal) {
+ track_normal = true;
+ BKE_shrinkwrap_compute_smooth_normal(&tree, NULL, nearest.index, nearest.co, nearest.no, track_no);
+ BLI_space_transform_invert_normal(&transform, track_no);
+ }
- BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData);
+ BKE_shrinkwrap_snap_point_to_surface(&tree, NULL, scon->shrinkMode, nearest.index, nearest.co, nearest.no, scon->dist, co, co);
+ }
+ else {
+ const float dist = len_v3v3(co, nearest.co);
- dist = len_v3v3(co, nearest.co);
- if (dist != 0.0f) {
- interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */
+ if (dist != 0.0f) {
+ interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */
+ }
}
+
BLI_space_transform_invert(&transform, co);
break;
}
@@ -3562,24 +3706,37 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
break;
}
- bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 4);
- if (treeData.tree == NULL) {
- fail = true;
- break;
+ char cull_mode = scon->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK;
+
+ BKE_shrinkwrap_project_normal(cull_mode, co, no, 0.0f, &transform, &tree, &hit);
+
+ if (scon->flag & CON_SHRINKWRAP_PROJECT_OPPOSITE) {
+ float inv_no[3];
+ negate_v3_v3(inv_no, no);
+
+ if ((scon->flag & CON_SHRINKWRAP_PROJECT_INVERT_CULL) && (cull_mode != 0)) {
+ cull_mode ^= CON_SHRINKWRAP_PROJECT_CULL_MASK;
+ }
+
+ BKE_shrinkwrap_project_normal(cull_mode, co, inv_no, 0.0f, &transform, &tree, &hit);
}
- if (BKE_shrinkwrap_project_normal(0, co, no, scon->dist, &transform, treeData.tree,
- &hit, treeData.raycast_callback, &treeData) == false)
- {
+ if (hit.index < 0) {
fail = true;
break;
}
- copy_v3_v3(co, hit.co);
+
+ if (do_track_normal) {
+ track_normal = true;
+ BKE_shrinkwrap_compute_smooth_normal(&tree, &transform, hit.index, hit.co, hit.no, track_no);
+ }
+
+ BKE_shrinkwrap_snap_point_to_surface(&tree, &transform, scon->shrinkMode, hit.index, hit.co, hit.no, scon->dist, co, co);
break;
}
}
- free_bvhtree_from_mesh(&treeData);
+ BKE_shrinkwrap_free_tree(&tree);
if (fail == true) {
/* Don't move the point */
@@ -3589,6 +3746,11 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
/* co is in local object coordinates, change it to global and update target position */
mul_m4_v3(cob->matrix, co);
copy_v3_v3(ct->matrix[3], co);
+
+ if (track_normal) {
+ mul_mat3_m4_v3(cob->matrix, track_no);
+ damptrack_do_transform(ct->matrix, track_no, scon->trackAxis);
+ }
}
}
}
@@ -3599,7 +3761,7 @@ static void shrinkwrap_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, Li
/* only evaluate if there is a target */
if (VALID_CONS_TARGET(ct)) {
- copy_v3_v3(cob->matrix[3], ct->matrix[3]);
+ copy_m4_m4(cob->matrix, ct->matrix);
}
}
@@ -3673,7 +3835,22 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
- float obvec[3], tarvec[3], obloc[3];
+ float tarvec[3];
+
+ /* find the (unit) direction vector going from the owner to the target */
+ sub_v3_v3v3(tarvec, ct->matrix[3], cob->matrix[3]);
+
+ damptrack_do_transform(cob->matrix, tarvec, data->trackflag);
+ }
+}
+
+static void damptrack_do_transform(float matrix[4][4], const float tarvec_in[3], int track_axis)
+{
+ /* find the (unit) direction vector going from the owner to the target */
+ float tarvec[3];
+
+ if (normalize_v3_v3(tarvec, tarvec_in) != 0.0f) {
+ float obvec[3], obloc[3];
float raxis[3], rangle;
float rmat[3][3], tmat[4][4];
@@ -3682,24 +3859,15 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
* - the normalization step at the end should take care of any unwanted scaling
* left over in the 3x3 matrix we used
*/
- copy_v3_v3(obvec, track_dir_vecs[data->trackflag]);
- mul_mat3_m4_v3(cob->matrix, obvec);
+ copy_v3_v3(obvec, track_dir_vecs[track_axis]);
+ mul_mat3_m4_v3(matrix, obvec);
if (normalize_v3(obvec) == 0.0f) {
/* exceptional case - just use the track vector as appropriate */
- copy_v3_v3(obvec, track_dir_vecs[data->trackflag]);
+ copy_v3_v3(obvec, track_dir_vecs[track_axis]);
}
- /* find the (unit) direction vector going from the owner to the target */
- copy_v3_v3(obloc, cob->matrix[3]);
- sub_v3_v3v3(tarvec, ct->matrix[3], obloc);
-
- if (normalize_v3(tarvec) == 0.0f) {
- /* the target is sitting on the owner, so just make them use the same direction vectors */
- /* FIXME: or would it be better to use the pure direction vector? */
- copy_v3_v3(tarvec, obvec);
- //copy_v3_v3(tarvec, track_dir_vecs[data->trackflag]);
- }
+ copy_v3_v3(obloc, matrix[3]);
/* determine the axis-angle rotation, which represents the smallest possible rotation
* between the two rotation vectors (i.e. the 'damping' referred to in the name)
@@ -3732,8 +3900,8 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
}
rangle = M_PI;
- copy_v3_v3(tmpvec, track_dir_vecs[(data->trackflag + 1) % 6]);
- mul_mat3_m4_v3(cob->matrix, tmpvec);
+ copy_v3_v3(tmpvec, track_dir_vecs[(track_axis + 1) % 6]);
+ mul_mat3_m4_v3(matrix, tmpvec);
cross_v3_v3v3(raxis, obvec, tmpvec);
if (normalize_v3(raxis) == 0.0f) {
@@ -3751,10 +3919,10 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
* we may have destroyed that in the process of multiplying the matrix
*/
unit_m4(tmat);
- mul_m4_m3m4(tmat, rmat, cob->matrix); // m1, m3, m2
+ mul_m4_m3m4(tmat, rmat, matrix); // m1, m3, m2
- copy_m4_m4(cob->matrix, tmat);
- copy_v3_v3(cob->matrix[3], obloc);
+ copy_m4_m4(matrix, tmat);
+ copy_v3_v3(matrix[3], obloc);
}
}
@@ -3837,16 +4005,10 @@ static void splineik_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
}
}
-static void splineik_get_tarmat(bConstraint *UNUSED(con), bConstraintOb *cob, bConstraintTarget *ct, float UNUSED(ctime))
+static void splineik_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
+ bConstraint *UNUSED(con), bConstraintOb *UNUSED(cob),
+ bConstraintTarget *ct, float UNUSED(ctime))
{
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (VALID_CONS_TARGET(ct)) {
- if (ct->tar->curve_cache == NULL) {
- BKE_displist_make_curveTypes(cob->scene, ct->tar, false);
- }
- }
-#endif
-
/* technically, this isn't really needed for evaluation, but we don't know what else
* might end up calling this...
*/
@@ -4014,20 +4176,25 @@ static void followtrack_id_looper(bConstraint *con, ConstraintIDFunc func, void
static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
+ Depsgraph *depsgraph = cob->depsgraph;
Scene *scene = cob->scene;
bFollowTrackConstraint *data = con->data;
MovieClip *clip = data->clip;
MovieTracking *tracking;
MovieTrackingTrack *track;
MovieTrackingObject *tracking_object;
- Object *camob = data->camera ? data->camera : scene->camera;
- float ctime = BKE_scene_frame_get(scene);
+
+ Object *camob_eval = DEG_get_evaluated_object(
+ depsgraph,
+ data->camera ? data->camera : scene->camera);
+
+ float ctime = DEG_get_ctime(depsgraph);
float framenr;
if (data->flag & FOLLOWTRACK_ACTIVECLIP)
clip = scene->clip;
- if (!clip || !data->track[0] || !camob)
+ if (!clip || !data->track[0] || !camob_eval)
return;
tracking = &clip->tracking;
@@ -4056,7 +4223,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
float imat[4][4];
- copy_m4_m4(mat, camob->obmat);
+ copy_m4_m4(mat, camob_eval->obmat);
BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, imat);
invert_m4(imat);
@@ -4065,7 +4232,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
}
else {
- BKE_tracking_get_camera_object_matrix(cob->scene, camob, mat);
+ BKE_tracking_get_camera_object_matrix(depsgraph, cob->scene, camob_eval, mat);
mul_m4_m4m4(cob->matrix, obmat, mat);
translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
@@ -4077,7 +4244,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp);
float len, d;
- BKE_object_where_is_calc_mat4(scene, camob, mat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, camob_eval, mat);
/* camera axis */
vec[0] = 0.0f;
@@ -4145,7 +4312,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
}
BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, camob);
+ BKE_camera_params_from_object(&params, camob_eval);
if (params.is_ortho) {
vec[0] = params.ortho_scale * (pos[0] - 0.5f + params.shiftx);
@@ -4157,9 +4324,9 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
else
vec[0] *= aspect;
- mul_v3_m4v3(disp, camob->obmat, vec);
+ mul_v3_m4v3(disp, camob_eval->obmat, vec);
- copy_m4_m4(rmat, camob->obmat);
+ copy_m4_m4(rmat, camob_eval->obmat);
zero_v3(rmat[3]);
mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
@@ -4177,10 +4344,10 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
else
vec[0] *= aspect;
- mul_v3_m4v3(disp, camob->obmat, vec);
+ mul_v3_m4v3(disp, camob_eval->obmat, vec);
/* apply camera rotation so Z-axis would be co-linear */
- copy_m4_m4(rmat, camob->obmat);
+ copy_m4_m4(rmat, camob_eval->obmat);
zero_v3(rmat[3]);
mul_m4_m4m4(cob->matrix, cob->matrix, rmat);
@@ -4189,9 +4356,8 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
if (data->depth_ob) {
Object *depth_ob = data->depth_ob;
- /* TODO(sergey): use proper for_render flag here when known. */
- DerivedMesh *target = object_get_derived_final(depth_ob, false);
- if (target) {
+ Mesh *target_eval = depth_ob->runtime.mesh_eval;
+ if (target_eval) {
BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeRayHit hit;
float ray_start[3], ray_end[3], ray_nor[3], imat[4][4];
@@ -4199,25 +4365,25 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
invert_m4_m4(imat, depth_ob->obmat);
- mul_v3_m4v3(ray_start, imat, camob->obmat[3]);
+ mul_v3_m4v3(ray_start, imat, camob_eval->obmat[3]);
mul_v3_m4v3(ray_end, imat, cob->matrix[3]);
sub_v3_v3v3(ray_nor, ray_end, ray_start);
normalize_v3(ray_nor);
- bvhtree_from_mesh_get(&treeData, target, BVHTREE_FROM_LOOPTRI, 4);
+ BKE_bvhtree_from_mesh_get(&treeData, target_eval, BVHTREE_FROM_LOOPTRI, 4);
hit.dist = BVH_RAYCAST_DIST_MAX;
hit.index = -1;
- result = BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData);
+ result = BLI_bvhtree_ray_cast(
+ treeData.tree, ray_start, ray_nor, 0.0f, &hit, treeData.raycast_callback, &treeData);
if (result != -1) {
mul_v3_m4v3(cob->matrix[3], depth_ob->obmat, hit.co);
}
free_bvhtree_from_mesh(&treeData);
- target->release(target);
}
}
}
@@ -4258,6 +4424,7 @@ static void camerasolver_id_looper(bConstraint *con, ConstraintIDFunc func, void
static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
+ Depsgraph *depsgraph = cob->depsgraph;
Scene *scene = cob->scene;
bCameraSolverConstraint *data = con->data;
MovieClip *clip = data->clip;
@@ -4269,7 +4436,7 @@ static void camerasolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
float mat[4][4], obmat[4][4];
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object = BKE_tracking_object_get_camera(tracking);
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = DEG_get_ctime(depsgraph);
float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
@@ -4316,6 +4483,7 @@ static void objectsolver_id_looper(bConstraint *con, ConstraintIDFunc func, void
static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *UNUSED(targets))
{
+ Depsgraph *depsgraph = cob->depsgraph;
Scene *scene = cob->scene;
bObjectSolverConstraint *data = con->data;
MovieClip *clip = data->clip;
@@ -4335,10 +4503,10 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
if (object) {
float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4];
- float ctime = BKE_scene_frame_get(scene);
+ float ctime = DEG_get_ctime(depsgraph);
float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
- BKE_object_where_is_calc_mat4(scene, camob, cammat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, camob, cammat);
BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
@@ -4390,7 +4558,7 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
return;
}
- const float frame = BKE_scene_frame_get(scene);
+ const float frame = DEG_get_ctime(cob->depsgraph);
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
BKE_cachefile_ensure_handle(G.main, cache_file);
@@ -4488,7 +4656,7 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[14] = &CTI_DISTLIMIT; /* Limit Distance Constraint */
constraintsTypeInfo[15] = &CTI_STRETCHTO; /* StretchTo Constaint */
constraintsTypeInfo[16] = &CTI_MINMAX; /* Floor Constraint */
- constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */
+ /* constraintsTypeInfo[17] = &CTI_RIGIDBODYJOINT; */ /* RigidBody Constraint - Deprecated */
constraintsTypeInfo[18] = &CTI_CLAMPTO; /* ClampTo Constraint */
constraintsTypeInfo[19] = &CTI_TRANSFORM; /* Transformation Constraint */
constraintsTypeInfo[20] = &CTI_SHRINKWRAP; /* Shrinkwrap Constraint */
@@ -4501,6 +4669,7 @@ static void constraints_init_typeinfo(void)
constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */
constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */
constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */
+ constraintsTypeInfo[30] = &CTI_ARMATURE; /* Armature Constraint */
}
/* This function should be used for getting the appropriate type-info when only
@@ -4640,7 +4809,7 @@ static bConstraint *add_new_constraint_internal(const char *name, short type)
/* Set up a generic constraint datablock */
con->type = type;
- con->flag |= CONSTRAINT_EXPAND;
+ con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_STATICOVERRIDE_LOCAL;
con->enforce = 1.0f;
/* Determine a basic name, and info */
@@ -4716,6 +4885,11 @@ static bConstraint *add_new_constraint(Object *ob, bPoseChannel *pchan, const ch
return con;
}
+bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *UNUSED(ct))
+{
+ return (con->flag & CONSTRAINT_BBONE_SHAPE) || (con->type == CONSTRAINT_TYPE_ARMATURE);
+}
+
/* ......... */
/* Add new constraint for the given bone */
@@ -4767,6 +4941,43 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool i
id_us_plus(*idpoin);
}
+/** Copies a single constraint's data (\a dst must already be a shallow copy of \a src). */
+static void constraint_copy_data_ex(bConstraint *dst, bConstraint *src, const int flag, const bool do_extern)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(src);
+
+ /* make a new copy of the constraint's data */
+ dst->data = MEM_dupallocN(dst->data);
+
+ /* only do specific constraints if required */
+ if (cti) {
+ /* perform custom copying operations if needed */
+ if (cti->copy_data)
+ cti->copy_data(dst, src);
+
+ /* Fix usercounts for all referenced data that need it. */
+ if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ cti->id_looper(dst, con_fix_copied_refs_cb, NULL);
+ }
+
+ /* for proxies we don't want to make extern */
+ if (do_extern) {
+ /* go over used ID-links for this constraint to ensure that they are valid for proxies */
+ if (cti->id_looper)
+ cti->id_looper(dst, con_extern_cb, NULL);
+ }
+ }
+}
+
+/** Allocate and duplicate a single constraint, ouside of any object/pose context. */
+bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern)
+{
+ bConstraint *dst = MEM_dupallocN(src);
+ constraint_copy_data_ex(dst, src, flag, do_extern);
+ dst->next = dst->prev = NULL;
+ return dst;
+}
+
/* duplicate all of the constraints in a constraint stack */
void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
{
@@ -4776,29 +4987,7 @@ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag,
BLI_duplicatelist(dst, src);
for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
- /* make a new copy of the constraint's data */
- con->data = MEM_dupallocN(con->data);
-
- /* only do specific constraints if required */
- if (cti) {
- /* perform custom copying operations if needed */
- if (cti->copy_data)
- cti->copy_data(con, srccon);
-
- /* Fix usercounts for all referenced data that need it. */
- if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- cti->id_looper(con, con_fix_copied_refs_cb, NULL);
- }
-
- /* for proxies we don't want to make extern */
- if (do_extern) {
- /* go over used ID-links for this constraint to ensure that they are valid for proxies */
- if (cti->id_looper)
- cti->id_looper(con, con_extern_cb, NULL);
- }
- }
+ constraint_copy_data_ex(con, srccon, flag, do_extern);
}
}
@@ -4846,6 +5035,48 @@ void BKE_constraints_active_set(ListBase *list, bConstraint *con)
}
}
+static bConstraint *constraint_list_find_from_target(ListBase *constraints, bConstraintTarget *tgt)
+{
+ for (bConstraint *con = constraints->first; con; con = con->next) {
+ ListBase *targets = NULL;
+
+ if (con->type == CONSTRAINT_TYPE_PYTHON) {
+ targets = &((bPythonConstraint *)con->data)->targets;
+ }
+ else if (con->type == CONSTRAINT_TYPE_ARMATURE) {
+ targets = &((bArmatureConstraint *)con->data)->targets;
+ }
+
+ if (targets && BLI_findindex(targets, tgt) != -1) {
+ return con;
+ }
+ }
+
+ return NULL;
+}
+
+/* Finds the constraint that owns the given target within the object. */
+bConstraint *BKE_constraint_find_from_target(Object *ob, bConstraintTarget *tgt)
+{
+ bConstraint *result = constraint_list_find_from_target(&ob->constraints, tgt);
+
+ if (result != NULL) {
+ return result;
+ }
+
+ if (ob->pose != NULL) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ result = constraint_list_find_from_target(&pchan->constraints, tgt);
+
+ if (result != NULL) {
+ return result;
+ }
+ }
+ }
+
+ return NULL;
+}
+
/* -------- Constraints and Proxies ------- */
/* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */
@@ -4895,7 +5126,7 @@ bool BKE_constraints_proxylocked_owner(Object *ob, bPoseChannel *pchan)
* None of the actual calculations of the matrices should be done here! Also, this function is
* not to be used by any new constraints, particularly any that have multiple targets.
*/
-void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime)
+void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph, Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime)
{
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
@@ -4907,6 +5138,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
cob = MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb");
cob->type = ownertype;
cob->scene = scene;
+ cob->depsgraph = depsgraph;
switch (ownertype) {
case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */
{
@@ -4946,7 +5178,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
if (ct) {
if (cti->get_target_matrix)
- cti->get_target_matrix(con, cob, ct, ctime);
+ cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
copy_m4_m4(mat, ct->matrix);
}
@@ -4962,7 +5194,7 @@ void BKE_constraint_target_matrix_get(Scene *scene, bConstraint *con, int index,
}
/* Get the list of targets required for solving a constraint */
-void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
+void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph, bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime)
{
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
@@ -4980,7 +5212,7 @@ void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob
*/
if (cti->get_target_matrix) {
for (ct = targets->first; ct; ct = ct->next)
- cti->get_target_matrix(con, cob, ct, ctime);
+ cti->get_target_matrix(depsgraph, con, cob, ct, ctime);
}
else {
for (ct = targets->first; ct; ct = ct->next)
@@ -4997,7 +5229,7 @@ void BKE_constraint_targets_for_solving_get(bConstraint *con, bConstraintOb *cob
* BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and
* after running this function, to sort out cob
*/
-void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime)
+void BKE_constraints_solve(struct Depsgraph *depsgraph, ListBase *conlist, bConstraintOb *cob, float ctime)
{
bConstraint *con;
float oldmat[4][4];
@@ -5032,7 +5264,7 @@ void BKE_constraints_solve(ListBase *conlist, bConstraintOb *cob, float ctime)
BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
/* prepare targets for constraint solving */
- BKE_constraint_targets_for_solving_get(con, cob, &targets, ctime);
+ BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime);
/* Solve the constraint and put result in cob->matrix */
cti->evaluate_constraint(con, cob, &targets);
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index c9468c7d95c..b3a26087dd0 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -38,6 +39,9 @@
#include "DNA_object_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_workspace_types.h"
+
+#include "DEG_depsgraph.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
@@ -47,9 +51,14 @@
#include "BLT_translation.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
+#include "BKE_workspace.h"
+
+#include "RE_engine.h"
#include "RNA_access.h"
@@ -66,10 +75,12 @@ struct bContext {
struct {
struct wmWindowManager *manager;
struct wmWindow *window;
+ struct WorkSpace *workspace;
struct bScreen *screen;
struct ScrArea *area;
struct ARegion *region;
struct ARegion *menu;
+ struct wmGizmoGroup *gizmo_group;
struct bContextStore *store;
const char *operator_poll_msg; /* reason for poll failing */
} wm;
@@ -83,13 +94,6 @@ struct bContext {
int py_init; /* true if python is initialized */
void *py_context;
} data;
-
- /* data evaluation */
-#if 0
- struct {
- int render;
- } eval;
-#endif
};
/* context */
@@ -627,6 +631,11 @@ wmWindow *CTX_wm_window(const bContext *C)
return ctx_wm_python_context_get(C, "window", &RNA_Window, C->wm.window);
}
+WorkSpace *CTX_wm_workspace(const bContext *C)
+{
+ return ctx_wm_python_context_get(C, "workspace", &RNA_WorkSpace, C->wm.workspace);
+}
+
bScreen *CTX_wm_screen(const bContext *C)
{
return ctx_wm_python_context_get(C, "screen", &RNA_Screen, C->wm.screen);
@@ -659,6 +668,16 @@ struct ARegion *CTX_wm_menu(const bContext *C)
return C->wm.menu;
}
+struct wmGizmoGroup *CTX_wm_gizmo_group(const bContext *C)
+{
+ return C->wm.gizmo_group;
+}
+
+struct wmMsgBus *CTX_wm_message_bus(const bContext *C)
+{
+ return C->wm.manager ? C->wm.manager->message_bus : NULL;
+}
+
struct ReportList *CTX_wm_reports(const bContext *C)
{
if (C->wm.manager)
@@ -750,14 +769,6 @@ struct SpaceNla *CTX_wm_space_nla(const bContext *C)
return NULL;
}
-struct SpaceTime *CTX_wm_space_time(const bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_TIME)
- return sa->spacedata.first;
- return NULL;
-}
-
struct SpaceNode *CTX_wm_space_node(const bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
@@ -766,14 +777,6 @@ struct SpaceNode *CTX_wm_space_node(const bContext *C)
return NULL;
}
-struct SpaceLogic *CTX_wm_space_logic(const bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_LOGIC)
- return sa->spacedata.first;
- return NULL;
-}
-
struct SpaceIpo *CTX_wm_space_graph(const bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
@@ -814,6 +817,14 @@ struct SpaceClip *CTX_wm_space_clip(const bContext *C)
return NULL;
}
+struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa && sa->spacetype == SPACE_TOPBAR)
+ return sa->spacedata.first;
+ return NULL;
+}
+
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
C->wm.manager = wm;
@@ -826,9 +837,11 @@ void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
void CTX_wm_window_set(bContext *C, wmWindow *win)
{
C->wm.window = win;
- C->wm.screen = (win) ? win->screen : NULL;
- if (C->wm.screen)
- C->data.scene = C->wm.screen->scene;
+ if (win) {
+ C->data.scene = win->scene;
+ }
+ C->wm.workspace = (win) ? BKE_workspace_active_get(win->workspace_hook) : NULL;
+ C->wm.screen = (win) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL;
C->wm.area = NULL;
C->wm.region = NULL;
}
@@ -836,8 +849,6 @@ void CTX_wm_window_set(bContext *C, wmWindow *win)
void CTX_wm_screen_set(bContext *C, bScreen *screen)
{
C->wm.screen = screen;
- if (C->wm.screen)
- C->data.scene = C->wm.screen->scene;
C->wm.area = NULL;
C->wm.region = NULL;
}
@@ -858,6 +869,11 @@ void CTX_wm_menu_set(bContext *C, ARegion *menu)
C->wm.menu = menu;
}
+void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup)
+{
+ C->wm.gizmo_group = gzgroup;
+}
+
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
{
C->wm.operator_poll_msg = msg;
@@ -896,10 +912,74 @@ Scene *CTX_data_scene(const bContext *C)
return C->data.scene;
}
-int CTX_data_mode_enum(const bContext *C)
+ViewLayer *CTX_data_view_layer(const bContext *C)
{
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer;
+
+ if (ctx_data_pointer_verify(C, "view_layer", (void *)&view_layer)) {
+ return view_layer;
+ }
+
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ if (win) {
+ view_layer = BKE_view_layer_find(scene, win->view_layer_name);
+ if (view_layer) {
+ return view_layer;
+ }
+ }
+
+ return BKE_view_layer_default_view(scene);
+}
+RenderEngineType *CTX_data_engine_type(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ return RE_engines_find(scene->r.engine);
+}
+
+/**
+ * This is tricky. Sometimes the user overrides the render_layer
+ * but not the scene_collection. In this case what to do?
+ *
+ * If the scene_collection is linked to the ViewLayer we use it.
+ * Otherwise we fallback to the active one of the ViewLayer.
+ */
+LayerCollection *CTX_data_layer_collection(const bContext *C)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ LayerCollection *layer_collection;
+
+ if (ctx_data_pointer_verify(C, "layer_collection", (void *)&layer_collection)) {
+ if (BKE_view_layer_has_collection(view_layer, layer_collection->collection)) {
+ return layer_collection;
+ }
+ }
+
+ /* fallback */
+ return BKE_layer_collection_get_active(view_layer);
+}
+
+Collection *CTX_data_collection(const bContext *C)
+{
+ Collection *collection;
+ if (ctx_data_pointer_verify(C, "collection", (void *)&collection)) {
+ return collection;
+ }
+
+ LayerCollection *layer_collection = CTX_data_layer_collection(C);
+ if (layer_collection) {
+ return layer_collection->collection;
+ }
+
+ /* fallback */
+ Scene *scene = CTX_data_scene(C);
+ return BKE_collection_master(scene);
+}
+
+int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectMode object_mode)
+{
+ // Object *obedit = CTX_data_edit_object(C);
if (obedit) {
switch (obedit->type) {
case OB_MESH:
@@ -919,21 +999,30 @@ int CTX_data_mode_enum(const bContext *C)
}
}
else {
- Object *ob = CTX_data_active_object(C);
-
+ // Object *ob = CTX_data_active_object(C);
if (ob) {
- if (ob->mode & OB_MODE_POSE) return CTX_MODE_POSE;
- else if (ob->mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT;
- else if (ob->mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT;
- else if (ob->mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
- else if (ob->mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
- else if (ob->mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
+ if (object_mode & OB_MODE_POSE) return CTX_MODE_POSE;
+ else if (object_mode & OB_MODE_SCULPT) return CTX_MODE_SCULPT;
+ else if (object_mode & OB_MODE_WEIGHT_PAINT) return CTX_MODE_PAINT_WEIGHT;
+ else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
+ else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
+ else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
+ else if (object_mode & OB_MODE_GPENCIL_PAINT) return CTX_MODE_GPENCIL_PAINT;
+ else if (object_mode & OB_MODE_GPENCIL_EDIT) return CTX_MODE_GPENCIL_EDIT;
+ else if (object_mode & OB_MODE_GPENCIL_SCULPT) return CTX_MODE_GPENCIL_SCULPT;
+ else if (object_mode & OB_MODE_GPENCIL_WEIGHT) return CTX_MODE_GPENCIL_WEIGHT;
}
}
return CTX_MODE_OBJECT;
}
+int CTX_data_mode_enum(const bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Object *obact = obedit ? NULL : CTX_data_active_object(C);
+ return CTX_data_mode_enum_ex(obedit, obact, obact ? obact->mode : OB_MODE_OBJECT);
+}
/* would prefer if we can use the enum version below over this one - Campbell */
/* must be aligned with above enum */
@@ -952,8 +1041,13 @@ static const char *data_mode_strings[] = {
"imagepaint",
"particlemode",
"objectmode",
+ "greasepencil_paint",
+ "greasepencil_edit",
+ "greasepencil_sculpt",
+ "greasepencil_weight",
NULL
};
+BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode")
const char *CTX_data_mode_string(const bContext *C)
{
return data_mode_strings[CTX_data_mode_enum(C)];
@@ -1104,6 +1198,11 @@ int CTX_data_selected_pose_bones(const bContext *C, ListBase *list)
return ctx_data_collection_get(C, "selected_pose_bones", list);
}
+int CTX_data_selected_pose_bones_from_active_object(const bContext *C, ListBase *list)
+{
+ return ctx_data_collection_get(C, "selected_pose_bones_from_active_object", list);
+}
+
int CTX_data_visible_pose_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "visible_pose_bones", list);
@@ -1119,17 +1218,7 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C)
return ctx_data_pointer_get(C, "active_gpencil_layer");
}
-bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C)
-{
- return ctx_data_pointer_get(C, "active_gpencil_palette");
-}
-
-bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C)
-{
- return ctx_data_pointer_get(C, "active_gpencil_palettecolor");
-}
-
-bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C)
+Brush *CTX_data_active_gpencil_brush(const bContext *C)
{
return ctx_data_pointer_get(C, "active_gpencil_brush");
}
@@ -1153,3 +1242,17 @@ int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "editable_gpencil_strokes", list);
}
+
+Depsgraph *CTX_data_depsgraph(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return BKE_scene_get_depsgraph(scene, view_layer, true);
+}
+
+Depsgraph *CTX_data_depsgraph_on_load(const bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ return BKE_scene_get_depsgraph(scene, view_layer, false);
+}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 56df8e51eba..354cc4926f1 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -48,6 +48,7 @@
#include "BKE_multires.h"
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
+#include "BKE_library.h"
BLI_INLINE void tan_calc_quat_v3(
float r_quat[4],
@@ -99,27 +100,26 @@ static int modifiers_disable_subsurf_temporary(Object *ob)
}
/* disable subsurf temporal, get mapped cos, and enable it */
-float (*BKE_crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3]
+float (*BKE_crazyspace_get_mapped_editverts(
+ struct Depsgraph *depsgraph, Scene *scene, Object *obedit))[3]
{
Mesh *me = obedit->data;
- DerivedMesh *dm;
+ Mesh *me_eval;
float (*vertexcos)[3];
int nverts = me->edit_btmesh->bm->totvert;
/* disable subsurf temporal, get mapped cos, and enable it */
if (modifiers_disable_subsurf_temporary(obedit)) {
/* need to make new derivemesh */
- makeDerivedMesh(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH, false);
+ makeDerivedMesh(depsgraph, scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH, false);
}
/* now get the cage */
vertexcos = MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map");
- dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
+ me_eval = editbmesh_get_eval_cage(depsgraph, scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
- mesh_get_mapped_verts_coords(dm, vertexcos, nverts);
-
- dm->release(dm);
+ mesh_get_mapped_verts_coords(me_eval, vertexcos, nverts);
/* set back the flag, no new cage needs to be built, transform does it */
modifiers_disable_subsurf_temporary(obedit);
@@ -250,19 +250,21 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me, float (*origcos)[3], float (*mapped
/** returns an array of deform matrices for crazyspace correction, and the
* number of modifiers left */
-int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob, BMEditMesh *em,
- float (**deformmats)[3][3], float (**deformcos)[3])
+int BKE_crazyspace_get_first_deform_matrices_editbmesh(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob, BMEditMesh *em,
+ float (**deformmats)[3][3], float (**deformcos)[3])
{
ModifierData *md;
- DerivedMesh *dm;
+ Mesh *me;
int i, a, numleft = 0, numVerts = 0;
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
VirtualModifierData virtualModifierData;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
modifiers_clearErrors(ob);
- dm = NULL;
+ me = NULL;
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* compute the deformation matrices and coordinates for the first
@@ -271,7 +273,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
for (i = 0; md && i <= cageIndex; i++, md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!editbmesh_modifier_is_enabled(scene, md, dm))
+ if (!editbmesh_modifier_is_enabled(scene, md, me != NULL))
continue;
if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
@@ -282,27 +284,26 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
data_mask = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, NULL);
- dm = getEditDerivedBMesh(em, ob, data_mask, NULL);
+ me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, data_mask, NULL);
deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");
for (a = 0; a < numVerts; a++)
unit_m3(defmats[a]);
}
-
- mti->deformMatricesEM(md, ob, em, dm, deformedVerts, defmats,
- numVerts);
+ mti->deformMatricesEM(md, &mectx, em, me, deformedVerts, defmats, numVerts);
}
else
break;
}
for (; md && i <= cageIndex; md = md->next, i++)
- if (editbmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md))
+ if (editbmesh_modifier_is_enabled(scene, md, me != NULL) && modifier_isCorrectableDeformed(md))
numleft++;
- if (dm)
- dm->release(dm);
+ if (me) {
+ BKE_id_free(NULL, me);
+ }
*deformmats = defmats;
*deformcos = deformedVerts;
@@ -310,16 +311,19 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob,
return numleft;
}
-int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
+int BKE_sculpt_get_first_deform_matrices(
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
{
ModifierData *md;
- DerivedMesh *dm;
+ Mesh *me_eval;
int a, numVerts = 0;
float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
int numleft = 0;
VirtualModifierData virtualModifierData;
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
if (has_multires) {
*deformmats = NULL;
@@ -327,7 +331,7 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
return numleft;
}
- dm = NULL;
+ me_eval = NULL;
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
for (; md; md = md->next) {
@@ -337,8 +341,8 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
if (mti->type == eModifierTypeType_OnlyDeform) {
if (!defmats) {
- Mesh *me = (Mesh *)ob->data;
- dm = mesh_create_derived(me, NULL);
+ Mesh *me = ob->data;
+ me_eval = BKE_mesh_copy_for_eval(me, true);
deformedVerts = BKE_mesh_vertexCos_get(me, &numVerts);
defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats");
@@ -346,7 +350,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
unit_m3(defmats[a]);
}
- if (mti->deformMatrices) mti->deformMatrices(md, ob, dm, deformedVerts, defmats, numVerts);
+ if (mti->deformMatrices) {
+ mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts);
+ }
else break;
}
}
@@ -360,8 +366,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
numleft++;
}
- if (dm)
- dm->release(dm);
+ if (me_eval) {
+ BKE_id_free(NULL, me_eval);
+ }
*deformmats = defmats;
*deformcos = deformedVerts;
@@ -369,9 +376,9 @@ int BKE_sculpt_get_first_deform_matrices(Scene *scene, Object *ob, float (**defo
return numleft;
}
-void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
+void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
{
- int totleft = BKE_sculpt_get_first_deform_matrices(scene, ob, deformmats, deformcos);
+ int totleft = BKE_sculpt_get_first_deform_matrices(depsgraph, scene, ob, deformmats, deformcos);
if (totleft) {
/* there are deformation modifier which doesn't support deformation matrices
@@ -383,6 +390,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[
int i, deformed = 0;
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
Mesh *me = (Mesh *)ob->data;
for (; md; md = md->next) {
@@ -396,7 +404,7 @@ void BKE_crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[
if (mti->deformMatrices && !deformed)
continue;
- mti->deformVerts(md, ob, NULL, deformedVerts, me->totvert, 0);
+ mti->deformVerts(md, &mectx, NULL, deformedVerts, me->totvert);
deformed = 1;
}
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index b395df49061..2f960a3a349 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -53,7 +53,6 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_font.h"
#include "BKE_global.h"
@@ -129,6 +128,8 @@ void BKE_curve_free(Curve *cu)
{
BKE_animdata_free((ID *)cu, false);
+ BKE_curve_batch_cache_free(cu);
+
BKE_nurbList_free(&cu->nurb);
BKE_curve_editfont_free(cu);
@@ -209,8 +210,9 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const
cu_dst->strinfo = MEM_dupallocN(cu_src->strinfo);
cu_dst->tb = MEM_dupallocN(cu_src->tb);
cu_dst->bb = MEM_dupallocN(cu_src->bb);
+ cu_dst->batch_cache = NULL;
- if (cu_src->key) {
+ if (cu_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &cu_src->key->id, (ID **)&cu_dst->key, flag, false);
}
@@ -221,7 +223,7 @@ void BKE_curve_copy_data(Main *bmain, Curve *cu_dst, const Curve *cu_src, const
Curve *BKE_curve_copy(Main *bmain, const Curve *cu)
{
Curve *cu_copy;
- BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, 0, false);
+ BKE_id_copy_ex(bmain, &cu->id, (ID **)&cu_copy, LIB_ID_COPY_SHAPEKEY, false);
return cu_copy;
}
@@ -1725,7 +1727,7 @@ float *BKE_curve_surf_make_orco(Object *ob)
/* NOTE: This routine is tied to the order of vertex
* built by displist and as passed to the renderer.
*/
-float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
+float *BKE_curve_make_orco(Depsgraph *depsgraph, Scene *scene, Object *ob, int *r_numVerts)
{
Curve *cu = ob->data;
DispList *dl;
@@ -1733,7 +1735,7 @@ float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
float *fp, *coord_array;
ListBase disp = {NULL, NULL};
- BKE_displist_make_curveTypes_forOrco(scene, ob, &disp);
+ BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
numVerts = 0;
for (dl = disp.first; dl; dl = dl->next) {
@@ -1824,8 +1826,9 @@ float *BKE_curve_make_orco(Scene *scene, Object *ob, int *r_numVerts)
/* ***************** BEVEL ****************** */
-void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
- const bool for_render, const bool use_render_resolution)
+void BKE_curve_bevel_make(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *disp,
+ const bool for_render, const bool use_render_resolution)
{
DispList *dl, *dlnew;
Curve *bevcu, *cu;
@@ -1849,14 +1852,14 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
facy = cu->bevobj->size[1];
if (for_render) {
- BKE_displist_make_curveTypes_forRender(scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution);
+ BKE_displist_make_curveTypes_forRender(depsgraph, scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution);
dl = bevdisp.first;
}
- else if (cu->bevobj->curve_cache) {
- dl = cu->bevobj->curve_cache->disp.first;
+ else if (cu->bevobj->runtime.curve_cache) {
+ dl = cu->bevobj->runtime.curve_cache->disp.first;
}
else {
- BLI_assert(cu->bevobj->curve_cache != NULL);
+ BLI_assert(cu->bevobj->runtime.curve_cache != NULL);
dl = NULL;
}
@@ -2769,14 +2772,14 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
- bev = &ob->curve_cache->bev;
+ bev = &ob->runtime.curve_cache->bev;
/* do we need to calculate the radius for each point? */
/* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */
/* STEP 1: MAKE POLYS */
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
nu = nurbs->first;
if (cu->editnurb && ob->type != OB_FONT) {
is_editmode = 1;
@@ -3407,44 +3410,16 @@ static void calchandleNurb_intern(
}
if (leftviolate || rightviolate) { /* align left handle */
BLI_assert(is_fcurve);
-#if 0
- if (is_fcurve)
-#endif
- {
- /* simple 2d calculation */
- float h1_x = p2_h1[0] - p2[0];
- float h2_x = p2[0] - p2_h2[0];
-
- if (leftviolate) {
- p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x;
- }
- else {
- p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x;
- }
+ /* simple 2d calculation */
+ float h1_x = p2_h1[0] - p2[0];
+ float h2_x = p2[0] - p2_h2[0];
+
+ if (leftviolate) {
+ p2_h2[1] = p2[1] + ((p2[1] - p2_h1[1]) / h1_x) * h2_x;
}
-#if 0
else {
- float h1[3], h2[3];
- float dot;
-
- sub_v3_v3v3(h1, p2_h1, p2);
- sub_v3_v3v3(h2, p2, p2_h2);
-
- len_a = normalize_v3(h1);
- len_b = normalize_v3(h2);
-
- dot = dot_v3v3(h1, h2);
-
- if (leftviolate) {
- mul_v3_fl(h1, dot * len_b);
- sub_v3_v3v3(p2_h2, p2, h1);
- }
- else {
- mul_v3_fl(h2, dot * len_a);
- add_v3_v3v3(p2_h1, p2, h2);
- }
+ p2_h1[1] = p2[1] + ((p2[1] - p2_h2[1]) / h2_x) * h1_x;
}
-#endif
}
}
}
@@ -4654,18 +4629,18 @@ float (*BKE_curve_nurbs_keyVertexCos_get(ListBase *lb, float *key))[3]
BezTriple *bezt = nu->bezt;
for (i = 0; i < nu->pntsu; i++, bezt++) {
- copy_v3_v3(co, key); co += 3; key += 3;
- copy_v3_v3(co, key); co += 3; key += 3;
- copy_v3_v3(co, key); co += 3; key += 3;
- key += 3; /* skip tilt */
+ copy_v3_v3(co, &key[0]); co += 3;
+ copy_v3_v3(co, &key[3]); co += 3;
+ copy_v3_v3(co, &key[6]); co += 3;
+ key += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
BPoint *bp = nu->bp;
for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
- copy_v3_v3(co, key); co += 3; key += 3;
- key++; /* skip tilt */
+ copy_v3_v3(co, key); co += 3;
+ key += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -4683,18 +4658,18 @@ void BKE_curve_nurbs_keyVertexTilts_apply(ListBase *lb, float *key)
BezTriple *bezt = nu->bezt;
for (i = 0; i < nu->pntsu; i++, bezt++) {
- key += 3 * 3;
- bezt->alfa = *key;
- key += 3;
+ bezt->alfa = key[9];
+ bezt->radius = key[10];
+ key += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
BPoint *bp = nu->bp;
for (i = 0; i < nu->pntsu * nu->pntsv; i++, bp++) {
- key += 3;
- bp->alfa = *key;
- key++;
+ bp->alfa = key[3];
+ bp->radius = key[4];
+ key += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -4864,11 +4839,6 @@ bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles)
nu->orderv = 1;
nu->type = type;
-#if 0 /* UNUSED */
- if (nu->flagu & CU_NURB_CYCLIC) c = nu->orderu - 1;
- else c = 0;
-#endif
-
if (type == CU_NURBS) {
nu->flagu &= CU_NURB_CYCLIC; /* disable all flags except for cyclic */
nu->flagu |= CU_NURB_BEZIER;
@@ -5010,12 +4980,6 @@ bool BKE_curve_nurb_vert_active_get(Curve *cu, Nurb **r_nu, void **r_vert)
vert = &nu->bp[cu->actvert];
}
}
- /* get functions should never set! */
-#if 0
- else {
- cu->actnu = cu->actvert = CU_ACT_NONE;
- }
-#endif
}
*r_nu = nu;
@@ -5164,8 +5128,29 @@ void BKE_curve_transform_ex(
KeyBlock *kb;
for (kb = cu->key->block.first; kb; kb = kb->next) {
float *fp = kb->data;
- for (i = kb->totelem; i--; fp += 3) {
- mul_m4_v3(mat, fp);
+ int n = kb->totelem;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
+ mul_m4_v3(mat, &fp[0]);
+ mul_m4_v3(mat, &fp[3]);
+ mul_m4_v3(mat, &fp[6]);
+ if (do_props) {
+ fp[10] *= unit_scale; /* radius */
+ }
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
+ mul_m4_v3(mat, fp);
+ if (do_props) {
+ fp[4] *= unit_scale; /* radius */
+ }
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
}
}
}
@@ -5209,8 +5194,23 @@ void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys)
KeyBlock *kb;
for (kb = cu->key->block.first; kb; kb = kb->next) {
float *fp = kb->data;
- for (i = kb->totelem; i--; fp += 3) {
- add_v3_v3(fp, offset);
+ int n = kb->totelem;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ for (i = nu->pntsu; i && (n -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; i--) {
+ add_v3_v3(&fp[0], offset);
+ add_v3_v3(&fp[3], offset);
+ add_v3_v3(&fp[6], offset);
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
+ }
+ }
+ else {
+ for (i = nu->pntsu * nu->pntsv; i && (n -= KEYELEM_ELEM_LEN_BPOINT) >= 0; i--) {
+ add_v3_v3(fp, offset);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
+ }
+ }
}
}
}
@@ -5288,7 +5288,7 @@ bool BKE_curve_material_index_validate(Curve *cu)
}
if (!is_valid) {
- DAG_id_tag_update(&cu->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&cu->id, OB_RECALC_DATA);
return true;
}
else {
@@ -5355,11 +5355,28 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t
/* **** Depsgraph evaluation **** */
-void BKE_curve_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+void BKE_curve_eval_geometry(Depsgraph *depsgraph,
Curve *curve)
{
- DEG_debug_print_eval(__func__, curve->id.name, curve);
+ DEG_debug_print_eval(depsgraph, __func__, curve->id.name, curve);
if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) {
BKE_curve_texspace_calc(curve);
}
}
+
+/* Draw Engine */
+void (*BKE_curve_batch_cache_dirty_tag_cb)(Curve *cu, int mode) = NULL;
+void (*BKE_curve_batch_cache_free_cb)(Curve *cu) = NULL;
+
+void BKE_curve_batch_cache_dirty_tag(Curve *cu, int mode)
+{
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_dirty_tag_cb(cu, mode);
+ }
+}
+void BKE_curve_batch_cache_free(Curve *cu)
+{
+ if (cu->batch_cache) {
+ BKE_curve_batch_cache_free_cb(cu);
+ }
+}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 8fa117dfce1..a0fa08708b1 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -53,6 +53,7 @@
#include "BKE_customdata.h"
#include "BKE_customdata_file.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
@@ -390,37 +391,19 @@ static void layerSwap_tface(void *data, const int *corner_indices)
{
MTFace *tf = data;
float uv[4][2];
- static const short pin_flags[4] = { TF_PIN1, TF_PIN2, TF_PIN3, TF_PIN4 };
- static const char sel_flags[4] = { TF_SEL1, TF_SEL2, TF_SEL3, TF_SEL4 };
- short unwrap = tf->unwrap & ~(TF_PIN1 | TF_PIN2 | TF_PIN3 | TF_PIN4);
- char flag = tf->flag & ~(TF_SEL1 | TF_SEL2 | TF_SEL3 | TF_SEL4);
int j;
for (j = 0; j < 4; ++j) {
const int source_index = corner_indices[j];
-
copy_v2_v2(uv[j], tf->uv[source_index]);
-
- /* swap pinning flags around */
- if (tf->unwrap & pin_flags[source_index]) {
- unwrap |= pin_flags[j];
- }
-
- /* swap selection flags around */
- if (tf->flag & sel_flags[source_index]) {
- flag |= sel_flags[j];
- }
}
memcpy(tf->uv, uv, sizeof(tf->uv));
- tf->unwrap = unwrap;
- tf->flag = flag;
}
static void layerDefault_tface(void *data, int count)
{
- static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, NULL,
- 0, 0, TF_DYNAMIC | TF_CONVERTED, 0, 0};
+ static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}};
MTFace *tf = (MTFace *)data;
int i;
@@ -489,11 +472,7 @@ static void layerInterp_origspace_face(
}
}
- /* delay writing to the destination incase dest is in sources */
-
-#if 0 /* no need, this ONLY contains UV's */
- *osf = *(OrigSpaceFace *)(*sources);
-#endif
+ /* delay writing to the destination in case dest is in sources */
memcpy(osf->uv, uv, sizeof(osf->uv));
}
@@ -1190,6 +1169,15 @@ static void layerSwap_flnor(void *data, const int *corner_indices)
memcpy(flnors, nors, sizeof(nors));
}
+static void layerDefault_fmap(void *data, int count)
+{
+ int *fmap_num = (int *)data;
+ int i;
+ for (i = 0; i < count; i++) {
+ *fmap_num = -1;
+ }
+}
+
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
@@ -1215,8 +1203,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 3 floats per normal vector */
{sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal},
- /* 9: CD_POLYINDEX */ /* DEPRECATED */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 9: CD_FACEMAP */
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
/* 10: CD_PROP_FLT */
{sizeof(MFloatProperty), "MFloatProperty", 1, N_("Float"), layerCopy_propFloat, NULL, NULL, NULL},
/* 11: CD_PROP_INT */
@@ -1228,10 +1216,9 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face},
/* 14: CD_ORCO */
{sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
- /* 15: CD_MTEXPOLY */
+ /* 15: CD_MTEXPOLY */ /* DEPRECATED */
/* note, when we expose the UV Map / TexFace split to the user, change this back to face Texture */
- {sizeof(MTexPoly), "MTexPoly", 1, N_("UVMap") /* "Face Texture" */, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_tface},
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 16: CD_MLOOPUV */
{sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap"), NULL, NULL, layerInterp_mloopuv, NULL, NULL,
layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv,
@@ -1310,7 +1297,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 0-4 */ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace",
- /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags",
+ /* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFaceMap",
/* 10-14 */ "CDMFloatProperty", "CDMIntProperty", "CDMStringProperty", "CDOrigSpace", "CDOrco",
/* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps",
/* 20-24 */ "CDPreviewMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDMRecast",
@@ -1325,41 +1312,41 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
const CustomDataMask CD_MASK_BAREMESH =
- CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT;
+ CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MLOOP | CD_MASK_MPOLY | CD_MASK_BWEIGHT | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_MESH =
CD_MASK_MVERT | CD_MASK_MEDGE |
CD_MASK_MDEFORMVERT |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP |
- CD_MASK_MTEXPOLY | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
+ CD_MASK_RECAST | CD_MASK_PAINT_MASK |
CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_EDITMESH =
CD_MASK_MDEFORMVERT | CD_MASK_MLOOPUV |
- CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX |
+ CD_MASK_MLOOPCOL | CD_MASK_SHAPE_KEYINDEX |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR |
CD_MASK_MDISPS | CD_MASK_SHAPEKEY | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MDEFORMVERT |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PREVIEW_MLOOPCOL |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL |
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT |
CD_MASK_PREVIEW_MCOL | CD_MASK_SHAPEKEY | CD_MASK_RECAST |
CD_MASK_ORIGINDEX | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
const CustomDataMask CD_MASK_BMESH =
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS |
CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
/**
* cover values copied by #BKE_mesh_loops_to_tessdata
*/
const CustomDataMask CD_MASK_FACECORNERS =
- CD_MASK_MTFACE | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
+ CD_MASK_MTFACE | CD_MASK_MLOOPUV |
CD_MASK_MCOL | CD_MASK_MLOOPCOL |
CD_MASK_PREVIEW_MCOL | CD_MASK_PREVIEW_MLOOPCOL |
CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP |
@@ -1368,7 +1355,7 @@ const CustomDataMask CD_MASK_FACECORNERS =
const CustomDataMask CD_MASK_EVERYTHING =
CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_NORMAL /* | CD_MASK_POLYINDEX */ | CD_MASK_PROP_FLT |
- CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
+ CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL | CD_MASK_TANGENT | CD_MASK_MDISPS | CD_MASK_PREVIEW_MCOL | CD_MASK_CLOTH_ORCO | CD_MASK_RECAST |
/* BMESH ONLY START */
CD_MASK_MPOLY | CD_MASK_MLOOP | CD_MASK_SHAPE_KEYINDEX | CD_MASK_SHAPEKEY | CD_MASK_BWEIGHT | CD_MASK_CREASE |
@@ -1376,7 +1363,7 @@ const CustomDataMask CD_MASK_EVERYTHING =
/* BMESH ONLY END */
CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN |
CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL;
+ CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_FACEMAP;
static const LayerTypeInfo *layerType_getInfo(int type)
{
@@ -1407,8 +1394,9 @@ void customData_mask_layers__print(CustomDataMask mask)
/********************* CustomData functions *********************/
static void customData_update_offsets(CustomData *data);
-static CustomDataLayer *customData_add_layer__internal(CustomData *data, int type, int alloctype, void *layerdata,
- int totelem, const char *name);
+static CustomDataLayer *customData_add_layer__internal(
+ CustomData *data, int type, eCDAllocType alloctype, void *layerdata,
+ int totelem, const char *name);
void CustomData_update_typemap(CustomData *data)
{
@@ -1437,8 +1425,9 @@ static bool customdata_typemap_is_valid(const CustomData *data)
}
#endif
-bool CustomData_merge(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem)
+bool CustomData_merge(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem)
{
/*const LayerTypeInfo *typeInfo;*/
CustomDataLayer *layer, *newlayer;
@@ -1520,8 +1509,9 @@ void CustomData_realloc(CustomData *data, int totelem)
}
}
-void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
- CustomDataMask mask, int alloctype, int totelem)
+void CustomData_copy(
+ const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, eCDAllocType alloctype, int totelem)
{
CustomData_reset(dest);
@@ -1820,8 +1810,9 @@ static int customData_resize(CustomData *data, int amount)
return 1;
}
-static CustomDataLayer *customData_add_layer__internal(CustomData *data, int type, int alloctype, void *layerdata,
- int totelem, const char *name)
+static CustomDataLayer *customData_add_layer__internal(
+ CustomData *data, int type, eCDAllocType alloctype, void *layerdata,
+ int totelem, const char *name)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
int flag = 0, index = data->totlayer;
@@ -1908,8 +1899,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, int typ
return &data->layers[index];
}
-void *CustomData_add_layer(CustomData *data, int type, int alloctype,
- void *layerdata, int totelem)
+void *CustomData_add_layer(
+ CustomData *data, int type, eCDAllocType alloctype,
+ void *layerdata, int totelem)
{
CustomDataLayer *layer;
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -1925,8 +1917,9 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype,
}
/*same as above but accepts a name*/
-void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
- void *layerdata, int totelem, const char *name)
+void *CustomData_add_layer_named(
+ CustomData *data, int type, eCDAllocType alloctype,
+ void *layerdata, int totelem, const char *name)
{
CustomDataLayer *layer;
@@ -2243,6 +2236,27 @@ void CustomData_copy_data(const CustomData *source, CustomData *dest,
}
}
+void CustomData_copy_layer_type_data(const CustomData *source,
+ CustomData *destination,
+ int type,
+ int source_index, int destination_index,
+ int count)
+{
+ const int source_layer_index = CustomData_get_layer_index(source, type);
+ if (source_layer_index == -1) {
+ return;
+ }
+ const int destinaiton_layer_index =
+ CustomData_get_layer_index(destination, type);
+ if (destinaiton_layer_index == -1) {
+ return;
+ }
+ CustomData_copy_data_layer(source, destination,
+ source_layer_index, destinaiton_layer_index,
+ source_index, destination_index,
+ count);
+}
+
void CustomData_free_elem(CustomData *data, int index, int count)
{
int i;
@@ -2501,13 +2515,10 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou
/* BMesh functions */
/* needed to convert to/from different face reps */
-void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata,
- int totloop, int totpoly)
+void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
{
- int i;
- for (i = 0; i < fdata->totlayer; i++) {
+ for (int i = 0; i < fdata->totlayer; i++) {
if (fdata->layers[i].type == CD_MTFACE) {
- CustomData_add_layer_named(pdata, CD_MTEXPOLY, CD_CALLOC, NULL, totpoly, fdata->layers[i].name);
CustomData_add_layer_named(ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MCOL) {
@@ -2522,19 +2533,18 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *l
}
}
-void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total)
+void CustomData_from_bmeshpoly(
+ CustomData *fdata, CustomData *ldata, int total)
{
int i;
/* avoid accumulating extra layers */
- BLI_assert(!CustomData_from_bmeshpoly_test(fdata, pdata, ldata, false));
+ BLI_assert(!CustomData_from_bmeshpoly_test(fdata, ldata, false));
- for (i = 0; i < pdata->totlayer; i++) {
- if (pdata->layers[i].type == CD_MTEXPOLY) {
- CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, pdata->layers[i].name);
- }
- }
for (i = 0; i < ldata->totlayer; i++) {
+ if (ldata->layers[i].type == CD_MLOOPUV) {
+ CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ }
if (ldata->layers[i].type == CD_MLOOPCOL) {
CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
}
@@ -2552,7 +2562,7 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData
}
}
- CustomData_bmesh_update_active_layers(fdata, pdata, ldata);
+ CustomData_bmesh_update_active_layers(fdata, ldata);
}
#ifndef NDEBUG
@@ -2562,13 +2572,13 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData
* \param fallback: Use when there are no layers to handle,
* since callers may expect success or failure.
*/
-bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, CustomData *ldata, bool fallback)
+bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback)
{
int a_num = 0, b_num = 0;
#define LAYER_CMP(l_a, t_a, l_b, t_b) \
((a_num += CustomData_number_of_layers(l_a, t_a)) == (b_num += CustomData_number_of_layers(l_b, t_b)))
- if (!LAYER_CMP(pdata, CD_MTEXPOLY, fdata, CD_MTFACE))
+ if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE))
return false;
if (!LAYER_CMP(ldata, CD_MLOOPCOL, fdata, CD_MCOL))
return false;
@@ -2590,25 +2600,21 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom
#endif
-void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
- if (CustomData_has_layer(pdata, CD_MTEXPOLY)) {
- act = CustomData_get_active_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
+ if (CustomData_has_layer(ldata, CD_MLOOPUV)) {
+ act = CustomData_get_active_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_active(fdata, CD_MTFACE, act);
- act = CustomData_get_render_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_render_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_render(fdata, CD_MTFACE, act);
- act = CustomData_get_clone_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_clone_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_clone(fdata, CD_MTFACE, act);
- act = CustomData_get_stencil_layer(pdata, CD_MTEXPOLY);
- CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
+ act = CustomData_get_stencil_layer(ldata, CD_MLOOPUV);
CustomData_set_layer_stencil(fdata, CD_MTFACE, act);
}
@@ -2632,25 +2638,21 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *pdata,
* used by do_versions in readfile.c when creating pdata and ldata for pre-bmesh
* meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files
*/
-void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
if (CustomData_has_layer(fdata, CD_MTFACE)) {
act = CustomData_get_active_layer(fdata, CD_MTFACE);
- CustomData_set_layer_active(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
act = CustomData_get_render_layer(fdata, CD_MTFACE);
- CustomData_set_layer_render(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
act = CustomData_get_clone_layer(fdata, CD_MTFACE);
- CustomData_set_layer_clone(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
act = CustomData_get_stencil_layer(fdata, CD_MTFACE);
- CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, act);
CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
}
@@ -2695,7 +2697,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
bool CustomData_bmesh_merge(
const CustomData *source, CustomData *dest,
- CustomDataMask mask, int alloctype, BMesh *bm, const char htype)
+ CustomDataMask mask, eCDAllocType alloctype, BMesh *bm, const char htype)
{
BMHeader *h;
BMIter iter;
@@ -3741,19 +3743,6 @@ void CustomData_external_remove(CustomData *data, ID *id, int type, int totelem)
CustomData_external_read(data, id, CD_TYPE_AS_MASK(layer->type), totelem);
layer->flag &= ~CD_FLAG_EXTERNAL;
-
-#if 0
- remove_file = 1;
- for (i = 0; i < data->totlayer; i++)
- if (data->layers[i].flag & CD_FLAG_EXTERNAL)
- remove_file = 0;
-
- if (remove_file) {
- customdata_external_filename(filename, id, external);
- cdf_remove(filename);
- CustomData_external_free(data);
- }
-#endif
}
}
@@ -3769,21 +3758,6 @@ bool CustomData_external_test(CustomData *data, int type)
return (layer->flag & CD_FLAG_EXTERNAL) != 0;
}
-#if 0
-void CustomData_external_remove_object(CustomData *data, ID *id)
-{
- CustomDataExternal *external = data->external;
- char filename[FILE_MAX];
-
- if (!external)
- return;
-
- customdata_external_filename(filename, id, external);
- cdf_remove(filename);
- CustomData_external_free(data);
-}
-#endif
-
/* ********** Mesh-to-mesh data transfer ********** */
static void copy_bit_flag(void *dst, const void *src, const size_t data_size, const uint64_t flag)
{
diff --git a/source/blender/blenkernel/intern/customdata_file.c b/source/blender/blenkernel/intern/customdata_file.c
index 3fee2ef6021..3350d8e7b2f 100644
--- a/source/blender/blenkernel/intern/customdata_file.c
+++ b/source/blender/blenkernel/intern/customdata_file.c
@@ -110,16 +110,6 @@ static int cdf_endian(void)
return CDF_ENDIAN_BIG;
}
-#if 0
-static int cdf_data_type_size(int datatype)
-{
- if (datatype == CDF_DATA_FLOAT)
- return sizeof(float);
-
- return 0;
-}
-#endif
-
CDataFile *cdf_create(int type)
{
CDataFile *cdf = MEM_callocN(sizeof(CDataFile), "CDataFile");
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 7407fc2051f..73c5f6cecdf 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -42,14 +42,13 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_mesh_remap.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
@@ -79,7 +78,7 @@ CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types
cddata_mask |= CD_MASK_MDEFORMVERT; /* Exception for vgroups :/ */
}
else if (cddata_type == CD_FAKE_UV) {
- cddata_mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV;
+ cddata_mask |= CD_MASK_MLOOPUV;
}
else if (cddata_type == CD_FAKE_LNOR) {
cddata_mask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
@@ -256,77 +255,76 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
/* Generic pre/post processing, only used by custom loop normals currently. */
static void data_transfer_dtdata_type_preprocess(
- Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
- const int dtdata_type, const bool dirty_nors_dst, const bool use_split_nors_src, const float split_angle_src)
+ Mesh *me_src, Mesh *me_dst,
+ const int dtdata_type, const bool dirty_nors_dst)
{
if (dtdata_type == DT_TYPE_LNOR) {
/* Compute custom normals into regular loop normals, which will be used for the transfer. */
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
- CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
const float split_angle_dst = me_dst->smoothresh;
- dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
+ BKE_mesh_calc_normals_split(me_src);
- if (dm_dst) {
- dm_dst->calcLoopNormals(dm_dst, use_split_nors_dst, split_angle_dst);
- }
- else {
- float (*poly_nors_dst)[3];
- float (*loop_nors_dst)[3];
- short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
-
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- if (dirty_nors_dst || !poly_nors_dst) {
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- BKE_mesh_calc_normals_poly(verts_dst, NULL, num_verts_dst, loops_dst, polys_dst,
- num_loops_dst, num_polys_dst, poly_nors_dst, true);
- }
- /* Cache loop nors into a temp CDLayer. */
- loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
- if (dirty_nors_dst || loop_nors_dst) {
- if (!loop_nors_dst) {
- loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
- CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- BKE_mesh_normals_loop_split(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
- loops_dst, loop_nors_dst, num_loops_dst,
- polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
- use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
- }
+ float (*poly_nors_dst)[3];
+ float (*loop_nors_dst)[3];
+ short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
+
+ /* Cache poly nors into a temp CDLayer. */
+ poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ const bool do_poly_nors_dst = (poly_nors_dst == NULL);
+ if (do_poly_nors_dst) {
+ poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
+ CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_poly_nors_dst) {
+ BKE_mesh_calc_normals_poly(
+ verts_dst, NULL, num_verts_dst, loops_dst, polys_dst,
+ num_loops_dst, num_polys_dst, poly_nors_dst, true);
+ }
+ /* Cache loop nors into a temp CDLayer. */
+ loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
+ const bool do_loop_nors_dst = (loop_nors_dst == NULL);
+ if (do_loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_loop_nors_dst) {
+ BKE_mesh_normals_loop_split(
+ verts_dst, num_verts_dst, edges_dst, num_edges_dst,
+ loops_dst, loop_nors_dst, num_loops_dst,
+ polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
+ use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
}
}
}
static void data_transfer_dtdata_type_postprocess(
- Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *UNUSED(dm_src), DerivedMesh *dm_dst, Mesh *me_dst,
+ Object *UNUSED(ob_src), Object *UNUSED(ob_dst), Mesh *UNUSED(me_src), Mesh *me_dst,
const int dtdata_type, const bool changed)
{
if (dtdata_type == DT_TYPE_LNOR) {
/* Bake edited destination loop normals into custom normals again. */
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
- CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL);
float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL);
@@ -530,7 +528,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
continue;
}
data_src = CustomData_get_layer_n(cd_src, cddata_type, idx_src);
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (fro; ;odifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_src, num_elem_dst);
}
@@ -574,7 +572,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(
data_dst_to_delete[idx_dst] = false;
}
if (r_map) {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -632,7 +630,7 @@ static bool data_transfer_layersmapping_cdlayers(
data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
}
else if (use_dupref_dst && r_map) {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
data_dst = CustomData_duplicate_referenced_layer(cd_dst, cddata_type, num_elem_dst);
}
@@ -659,7 +657,7 @@ static bool data_transfer_layersmapping_cdlayers(
if (tolayers >= 0) { /* Real-layer index */
idx_dst = tolayers;
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -675,7 +673,7 @@ static bool data_transfer_layersmapping_cdlayers(
data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
}
else {
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -696,7 +694,7 @@ static bool data_transfer_layersmapping_cdlayers(
CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst);
}
}
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -713,7 +711,7 @@ static bool data_transfer_layersmapping_cdlayers(
CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name);
idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name);
}
- /* If dest is a derivedmesh, we do not want to overwrite cdlayers of org mesh! */
+ /* If dest is a evaluated mesh (from modifier), we do not want to overwrite cdlayers of orig mesh! */
if (use_dupref_dst && r_map) {
data_dst = CustomData_duplicate_referenced_layer_n(cd_dst, cddata_type, idx_dst, num_elem_dst);
}
@@ -762,7 +760,7 @@ static bool data_transfer_layersmapping_cdlayers(
}
static bool data_transfer_layersmapping_generate(
- ListBase *r_map, Object *ob_src, Object *ob_dst, DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
+ ListBase *r_map, Object *ob_src, Object *ob_dst, Mesh *me_src, Mesh *me_dst,
const int elem_type, int cddata_type, int mix_mode, float mix_factor, const float *mix_weights,
const int num_elem_dst, const bool use_create, const bool use_delete, const int fromlayers, const int tolayers,
SpaceTransform *space_transform)
@@ -774,12 +772,12 @@ static bool data_transfer_layersmapping_generate(
if (elem_type == ME_VERT) {
if (!(cddata_type & CD_FAKE)) {
- cd_src = dm_src->getVertDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata;
+ cd_src = &me_src->vdata;
+ cd_dst = &me_dst->vdata;
if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
- cd_src, cd_dst, dm_dst != NULL,
+ cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -794,24 +792,17 @@ static bool data_transfer_layersmapping_generate(
const size_t data_offset = offsetof(MVert, bweight);
const uint64_t data_flag = 0;
- if (!(dm_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) {
- if (use_delete && !dm_dst) {
+ if (!(me_src->cd_flag & ME_CDFLAG_VERT_BWEIGHT)) {
+ if (use_delete) {
me_dst->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT;
}
return true;
}
- if (dm_dst) {
- dm_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- }
- else {
- me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
- }
+ me_dst->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
if (r_map) {
data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getVertArray(dm_src),
- dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert,
- dm_src->getNumVerts(dm_src),
- dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert,
+ me_src->mvert, me_dst->mvert,
+ me_src->totvert, me_dst->totvert,
elem_size, data_size, data_offset, data_flag,
data_transfer_interp_char, interp_data);
}
@@ -820,12 +811,12 @@ static bool data_transfer_layersmapping_generate(
else if (cddata_type == CD_FAKE_MDEFORMVERT) {
bool ret;
- cd_src = dm_src->getVertDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata;
+ cd_src = &me_src->vdata;
+ cd_dst = &me_dst->vdata;
ret = data_transfer_layersmapping_vgroups(r_map, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
- ob_src, ob_dst, cd_src, cd_dst, dm_dst != NULL,
+ ob_src, ob_dst, cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers);
/* Mesh stores its dvert in a specific pointer too. :( */
@@ -839,12 +830,12 @@ static bool data_transfer_layersmapping_generate(
}
else if (elem_type == ME_EDGE) {
if (!(cddata_type & CD_FAKE)) { /* Unused for edges, currently... */
- cd_src = dm_src->getEdgeDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getEdgeDataLayout(dm_dst) : &me_dst->edata;
+ cd_src = &me_src->edata;
+ cd_dst = &me_dst->edata;
if (!data_transfer_layersmapping_cdlayers(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
num_elem_dst, use_create, use_delete,
- cd_src, cd_dst, dm_dst != NULL,
+ cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -859,24 +850,17 @@ static bool data_transfer_layersmapping_generate(
const size_t data_offset = offsetof(MEdge, crease);
const uint64_t data_flag = 0;
- if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
- if (use_delete && !dm_dst) {
+ if (!(me_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
+ if (use_delete && !me_dst) {
me_dst->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
}
return true;
}
- if (dm_dst) {
- dm_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
- else {
- me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
+ me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
if (r_map) {
data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getEdgeArray(dm_src),
- dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
- dm_src->getNumEdges(dm_src),
- dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
+ me_src->medge, me_dst->medge,
+ me_src->totedge, me_dst->totedge,
elem_size, data_size, data_offset, data_flag,
data_transfer_interp_char, interp_data);
}
@@ -888,24 +872,17 @@ static bool data_transfer_layersmapping_generate(
const size_t data_offset = offsetof(MEdge, bweight);
const uint64_t data_flag = 0;
- if (!(dm_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) {
- if (use_delete && !dm_dst) {
+ if (!(me_src->cd_flag & ME_CDFLAG_EDGE_BWEIGHT)) {
+ if (use_delete && !me_dst) {
me_dst->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT;
}
return true;
}
- if (dm_dst) {
- dm_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- }
- else {
- me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
- }
+ me_dst->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
if (r_map) {
data_transfer_layersmapping_add_item(r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getEdgeArray(dm_src),
- dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
- dm_src->getNumEdges(dm_src),
- dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
+ me_src->medge, me_dst->medge,
+ me_src->totedge, me_dst->totedge,
elem_size, data_size, data_offset, data_flag,
data_transfer_interp_char, interp_data);
}
@@ -919,10 +896,8 @@ static bool data_transfer_layersmapping_generate(
data_transfer_layersmapping_add_item(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getEdgeArray(dm_src),
- dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge,
- dm_src->getNumEdges(dm_src),
- dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge,
+ me_src->medge, me_dst->medge,
+ me_src->totedge, me_dst->totedge,
elem_size, data_size, data_offset, data_flag, NULL, interp_data);
return true;
}
@@ -942,12 +917,12 @@ static bool data_transfer_layersmapping_generate(
}
if (!(cddata_type & CD_FAKE)) {
- cd_src = dm_src->getLoopDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ cd_src = &me_src->ldata;
+ cd_dst = &me_dst->ldata;
if (!data_transfer_layersmapping_cdlayers(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
+ num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -962,16 +937,16 @@ static bool data_transfer_layersmapping_generate(
}
else if (elem_type == ME_POLY) {
if (cddata_type == CD_FAKE_UV) {
- cddata_type = CD_MTEXPOLY;
+ cddata_type = CD_MLOOPUV;
}
if (!(cddata_type & CD_FAKE)) {
- cd_src = dm_src->getPolyDataLayout(dm_src);
- cd_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
+ cd_src = &me_src->pdata;
+ cd_dst = &me_dst->pdata;
if (!data_transfer_layersmapping_cdlayers(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete, cd_src, cd_dst, dm_dst != NULL,
+ num_elem_dst, use_create, use_delete, cd_src, cd_dst, me_dst != ob_dst->data,
fromlayers, tolayers,
interp, interp_data))
{
@@ -988,10 +963,8 @@ static bool data_transfer_layersmapping_generate(
data_transfer_layersmapping_add_item(
r_map, cddata_type, mix_mode, mix_factor, mix_weights,
- dm_src->getPolyArray(dm_src),
- dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly,
- dm_src->getNumPolys(dm_src),
- dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly,
+ me_src->mpoly, me_dst->mpoly,
+ me_src->totpoly, me_dst->totpoly,
elem_size, data_size, data_offset, data_flag, NULL, interp_data);
return true;
}
@@ -1010,25 +983,26 @@ static bool data_transfer_layersmapping_generate(
* to get (as much as possible) exact copy of source data layout.
*/
void BKE_object_data_transfer_layout(
- Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete,
+ struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob_src, Object *ob_dst, const int data_types, const bool use_delete,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX])
{
- DerivedMesh *dm_src;
+ Mesh *me_src;
Mesh *me_dst;
int i;
const bool use_create = true; /* We always create needed layers here. */
- CustomDataMask dm_src_mask = CD_MASK_BAREMESH;
+ CustomDataMask me_src_mask = CD_MASK_BAREMESH;
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
me_dst = ob_dst->data;
- /* Get source DM.*/
- dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
- dm_src = mesh_get_derived_final(scene, ob_src, dm_src_mask);
- if (!dm_src) {
+ /* Get source evaluated mesh.*/
+ me_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
+ me_src = mesh_get_eval_final(depsgraph, scene, ob_src, me_src_mask);
+ if (!me_src) {
return;
}
@@ -1057,37 +1031,37 @@ void BKE_object_data_transfer_layout(
const int num_elem_dst = me_dst->totvert;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_VERT, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
const int num_elem_dst = me_dst->totedge;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_EDGE, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
const int num_elem_dst = me_dst->totloop;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_LOOP, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
if (DT_DATATYPE_IS_POLY(dtdata_type)) {
const int num_elem_dst = me_dst->totpoly;
data_transfer_layersmapping_generate(
- NULL, ob_src, ob_dst, dm_src, NULL, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL,
+ NULL, ob_src, ob_dst, me_src, me_dst, ME_POLY, cddata_type, 0, 0.0f, NULL,
num_elem_dst, use_create, use_delete, fromlayers, tolayers, NULL);
}
}
}
-bool BKE_object_data_transfer_dm(
- Scene *scene, Object *ob_src, Object *ob_dst, DerivedMesh *dm_dst, const int data_types, bool use_create,
- const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
- SpaceTransform *space_transform, const bool auto_transform,
+bool BKE_object_data_transfer_ex(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, Mesh *me_dst,
+ const int data_types, bool use_create, const int map_vert_mode, const int map_edge_mode,
+ const int map_loop_mode, const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform,
const float max_distance, const float ray_radius, const float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
@@ -1101,9 +1075,8 @@ bool BKE_object_data_transfer_dm(
SpaceTransform auto_space_transform;
- DerivedMesh *dm_src;
- Mesh *me_dst, *me_src;
- bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */
+ Mesh *me_src;
+ bool dirty_nors_dst = true; /* Assumed always true if not using an evaluated mesh as destination. */
int i;
MDeformVert *mdef = NULL;
@@ -1117,53 +1090,40 @@ bool BKE_object_data_transfer_dm(
const bool use_delete = false; /* We never delete data layers from destination here. */
- CustomDataMask dm_src_mask = CD_MASK_BAREMESH;
+ CustomDataMask me_src_mask = CD_MASK_BAREMESH;
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
- me_dst = ob_dst->data;
- me_src = ob_src->data;
- if (dm_dst) {
- dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0;
- use_create = false; /* Never create needed custom layers on DM (modifier case). */
+ if (me_dst) {
+ dirty_nors_dst = (me_dst->runtime.cd_dirty_vert & CD_NORMAL) != 0;
+ /* Never create needed custom layers on passed destination mesh
+ * (assumed to *not* be ob_dst->data, aka modifier case). */
+ use_create = false;
+ }
+ else {
+ me_dst = ob_dst->data;
}
if (vgroup_name) {
- if (dm_dst) {
- mdef = dm_dst->getVertDataArray(dm_dst, CD_MDEFORMVERT);
- }
- else {
- mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
- }
+ mdef = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
if (mdef) {
vg_idx = defgroup_name_index(ob_dst, vgroup_name);
}
}
- /* Get source DM.*/
- dm_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
- /* XXX Hack! In case this is being evaluated from dm stack, we cannot compute final dm,
- * can lead to infinite recursion in case of dependency cycles of DataTransfer modifiers...
- * Issue is, this means we cannot be sure to have requested cd layers in source.
- *
- * Also, we need to make a local copy of dm_src, otherwise we may end with concurrent creation
- * of data in it (multi-threaded evaluation of the modifier stack, see T46672).
- */
- dm_src = dm_dst ? ob_src->derivedFinal : mesh_get_derived_final(scene, ob_src, dm_src_mask);
- if (!dm_src) {
+ /* Get source evaluated mesh.*/
+ me_src_mask |= BKE_object_data_transfer_dttypes_to_cdmask(data_types);
+ me_src = mesh_get_eval_final(depsgraph, scene, ob_src, me_src_mask);
+ if (!me_src) {
return changed;
}
- dm_src = CDDM_copy(dm_src);
if (auto_transform) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
-
if (space_transform == NULL) {
space_transform = &auto_space_transform;
}
- BKE_mesh_remap_find_best_match_from_dm(verts_dst, num_verts_dst, dm_src, space_transform);
+ BKE_mesh_remap_find_best_match_from_mesh(me_dst->mvert, me_dst->totvert, me_src, space_transform);
}
/* Check all possible data types.
@@ -1177,9 +1137,7 @@ bool BKE_object_data_transfer_dm(
continue;
}
- data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst,
- dtdata_type, dirty_nors_dst,
- (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh);
+ data_transfer_dtdata_type_preprocess(me_src, me_dst, dtdata_type, dirty_nors_dst);
cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
@@ -1193,11 +1151,11 @@ bool BKE_object_data_transfer_dm(
}
if (DT_DATATYPE_IS_VERT(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
if (!geom_map_init[VDATA]) {
- const int num_verts_src = dm_src->getNumVerts(dm_src);
+ const int num_verts_src = me_src->totvert;
if ((map_vert_mode == MREMAP_MODE_TOPOLOGY) && (num_verts_dst != num_verts_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1205,13 +1163,13 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_vert_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ if ((map_vert_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any edges, "
"None of the 'Edge' mappings can be used in this case");
continue;
}
- if ((map_vert_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ if ((map_vert_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any faces, "
"None of the 'Face' mappings can be used in this case");
@@ -1223,9 +1181,9 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_verts_from_dm(
+ BKE_mesh_remap_calc_verts_from_mesh(
map_vert_mode, space_transform, max_distance, ray_radius,
- verts_dst, num_verts_dst, dirty_nors_dst, dm_src, &geom_map[VDATA]);
+ verts_dst, num_verts_dst, dirty_nors_dst, me_src, &geom_map[VDATA]);
geom_map_init[VDATA] = true;
}
@@ -1235,7 +1193,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_VERT,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_VERT,
cddata_type, mix_mode, mix_factor, weights[VDATA],
num_verts_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1251,13 +1209,13 @@ bool BKE_object_data_transfer_dm(
}
}
if (DT_DATATYPE_IS_EDGE(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
if (!geom_map_init[EDATA]) {
- const int num_edges_src = dm_src->getNumEdges(dm_src);
+ const int num_edges_src = me_src->totedge;
if ((map_edge_mode == MREMAP_MODE_TOPOLOGY) && (num_edges_dst != num_edges_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1265,7 +1223,7 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_edge_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) {
+ if ((map_edge_mode & MREMAP_USE_POLY) && (me_src->totpoly == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any faces, "
"None of the 'Face' mappings can be used in this case");
@@ -1277,10 +1235,10 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_edges_from_dm(
+ BKE_mesh_remap_calc_edges_from_mesh(
map_edge_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst, dirty_nors_dst,
- dm_src, &geom_map[EDATA]);
+ me_src, &geom_map[EDATA]);
geom_map_init[EDATA] = true;
}
@@ -1292,7 +1250,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_EDGE,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_EDGE,
cddata_type, mix_mode, mix_factor, weights[EDATA],
num_edges_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1308,21 +1266,21 @@ bool BKE_object_data_transfer_dm(
}
}
if (DT_DATATYPE_IS_LOOP(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
- const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
- CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MEdge *edges_dst = me_dst->medge;
+ const int num_edges_dst = me_dst->totedge;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
+ CustomData *ldata_dst = &me_dst->ldata;
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
if (!geom_map_init[LDATA]) {
- const int num_loops_src = dm_src->getNumLoops(dm_src);
+ const int num_loops_src = me_src->totloop;
if ((map_loop_mode == MREMAP_MODE_TOPOLOGY) && (num_loops_dst != num_loops_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1330,7 +1288,7 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_loop_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ if ((map_loop_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any edges, "
"None of the 'Edge' mappings can be used in this case");
@@ -1342,13 +1300,13 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_loops_from_dm(
+ BKE_mesh_remap_calc_loops_from_mesh(
map_loop_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst,
loops_dst, num_loops_dst, polys_dst, num_polys_dst,
ldata_dst, pdata_dst,
(me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst,
- dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh,
+ me_src,
island_callback, islands_handling_precision, &geom_map[LDATA]);
geom_map_init[LDATA] = true;
}
@@ -1361,7 +1319,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_LOOP,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_LOOP,
cddata_type, mix_mode, mix_factor, weights[LDATA],
num_loops_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1377,16 +1335,16 @@ bool BKE_object_data_transfer_dm(
}
}
if (DT_DATATYPE_IS_POLY(dtdata_type)) {
- MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
- const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
- MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
- const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
- MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
- const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
- CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
+ MVert *verts_dst = me_dst->mvert;
+ const int num_verts_dst = me_dst->totvert;
+ MPoly *polys_dst = me_dst->mpoly;
+ const int num_polys_dst = me_dst->totpoly;
+ MLoop *loops_dst = me_dst->mloop;
+ const int num_loops_dst = me_dst->totloop;
+ CustomData *pdata_dst = &me_dst->pdata;
if (!geom_map_init[PDATA]) {
- const int num_polys_src = dm_src->getNumPolys(dm_src);
+ const int num_polys_src = me_src->totpoly;
if ((map_poly_mode == MREMAP_MODE_TOPOLOGY) && (num_polys_dst != num_polys_src)) {
BKE_report(reports, RPT_ERROR,
@@ -1394,7 +1352,7 @@ bool BKE_object_data_transfer_dm(
"'Topology' mapping cannot be used in this case");
continue;
}
- if ((map_poly_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) {
+ if ((map_poly_mode & MREMAP_USE_EDGE) && (me_src->totedge == 0)) {
BKE_report(reports, RPT_ERROR,
"Source mesh doesn't have any edges, "
"None of the 'Edge' mappings can be used in this case");
@@ -1406,11 +1364,11 @@ bool BKE_object_data_transfer_dm(
continue;
}
- BKE_mesh_remap_calc_polys_from_dm(
+ BKE_mesh_remap_calc_polys_from_mesh(
map_poly_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, loops_dst, num_loops_dst,
polys_dst, num_polys_dst, pdata_dst, dirty_nors_dst,
- dm_src, &geom_map[PDATA]);
+ me_src, &geom_map[PDATA]);
geom_map_init[PDATA] = true;
}
@@ -1422,7 +1380,7 @@ bool BKE_object_data_transfer_dm(
}
if (data_transfer_layersmapping_generate(
- &lay_map, ob_src, ob_dst, dm_src, dm_dst, me_dst, ME_POLY,
+ &lay_map, ob_src, ob_dst, me_src, me_dst, ME_POLY,
cddata_type, mix_mode, mix_factor, weights[PDATA],
num_polys_dst, use_create, use_delete, fromlayers, tolayers, space_transform))
{
@@ -1438,14 +1396,13 @@ bool BKE_object_data_transfer_dm(
}
}
- data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed);
+ data_transfer_dtdata_type_postprocess(ob_src, ob_dst, me_src, me_dst, dtdata_type, changed);
}
for (i = 0; i < DATAMAX; i++) {
BKE_mesh_remap_free(&geom_map[i]);
MEM_SAFE_FREE(weights[i]);
}
- dm_src->release(dm_src);
return changed;
@@ -1457,16 +1414,16 @@ bool BKE_object_data_transfer_dm(
}
bool BKE_object_data_transfer_mesh(
- Scene *scene, Object *ob_src, Object *ob_dst, const int data_types, const bool use_create,
- const int map_vert_mode, const int map_edge_mode, const int map_loop_mode, const int map_poly_mode,
- SpaceTransform *space_transform, const bool auto_transform,
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob_src, Object *ob_dst, const int data_types,
+ const bool use_create, const int map_vert_mode, const int map_edge_mode, const int map_loop_mode,
+ const int map_poly_mode, SpaceTransform *space_transform, const bool auto_transform,
const float max_distance, const float ray_radius, const float islands_handling_precision,
const int fromlayers_select[DT_MULTILAYER_INDEX_MAX], const int tolayers_select[DT_MULTILAYER_INDEX_MAX],
const int mix_mode, const float mix_factor, const char *vgroup_name, const bool invert_vgroup,
ReportList *reports)
{
- return BKE_object_data_transfer_dm(
- scene, ob_src, ob_dst, NULL, data_types, use_create,
+ return BKE_object_data_transfer_ex(
+ depsgraph, scene, ob_src, ob_dst, NULL, data_types, use_create,
map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode,
space_transform, auto_transform,
max_distance, ray_radius, islands_handling_precision,
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index f33f17019b3..bbb7fc4b3bd 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -54,7 +54,9 @@
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h" /* own include */
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "data_transfer_intern.h"
@@ -73,6 +75,8 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name)
BLI_addtail(&ob->defbase, defgroup);
defgroup_unique_name(defgroup, ob);
+ BKE_object_batch_cache_dirty_tag(ob);
+
return defgroup;
}
@@ -1290,3 +1294,43 @@ bool data_transfer_layersmapping_vgroups(
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Various utils & helpers.
+ * \{ */
+
+void BKE_defvert_weight_to_rgb(float r_rgb[3], const float weight)
+{
+ const float blend = ((weight / 2.0f) + 0.5f);
+
+ if (weight <= 0.25f) { /* blue->cyan */
+ r_rgb[0] = 0.0f;
+ r_rgb[1] = blend * weight * 4.0f;
+ r_rgb[2] = blend;
+ }
+ else if (weight <= 0.50f) { /* cyan->green */
+ r_rgb[0] = 0.0f;
+ r_rgb[1] = blend;
+ r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
+ }
+ else if (weight <= 0.75f) { /* green->yellow */
+ r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
+ r_rgb[1] = blend;
+ r_rgb[2] = 0.0f;
+ }
+ else if (weight <= 1.0f) { /* yellow->red */
+ r_rgb[0] = blend;
+ r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
+ r_rgb[2] = 0.0f;
+ }
+ else {
+ /* exceptional value, unclamped or nan,
+ * avoid uninitialized memory use */
+ r_rgb[0] = 1.0f;
+ r_rgb[1] = 0.0f;
+ r_rgb[2] = 1.0f;
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
deleted file mode 100644
index 734aac8a1f7..00000000000
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ /dev/null
@@ -1,3745 +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 "DNA_modifier_types.h"
-#include "DNA_rigidbody_types.h"
-
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
-#include "BKE_action.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_collision.h"
-#include "BKE_curve.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 create_collision_relation(DagForest *dag, DagNode *node, Object *ob1, const char *name)
-{
- DagNode *node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, name);
-}
-
-void dag_add_collision_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, Group *group, int layer, unsigned int modifier_type, DagCollobjFilterFunction fn, bool dupli, const char *name)
-{
- unsigned int numcollobj;
- Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli);
-
- for (unsigned int i = 0; i < numcollobj; i++) {
- Object *ob1 = collobjs[i];
-
- if (!fn || fn(ob1, modifiers_findByType(ob1, modifier_type))) {
- create_collision_relation(dag, node, ob1, name);
- }
- }
-
- if (collobjs)
- MEM_freeN(collobjs);
-}
-
-void dag_add_forcefield_relations(DagForest *dag, Scene *scene, Object *ob, DagNode *node, 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 = effectors->first; eff; eff = eff->next) {
- if (eff->ob != ob && eff->pd->forcefield != skip_forcefield) {
- create_collision_relation(dag, node, eff->ob, name);
-
- if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- create_collision_relation(dag, node, eff->pd->f_source, "Smoke Force Domain");
- }
-
- if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
- /* Actual code uses get_collider_cache */
- dag_add_collision_relations(dag, scene, ob, node, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption");
- }
- }
- }
- }
-
- pdEndEffectors(&effectors);
-}
-
-static bool build_deg_tracking_constraints(DagForest *dag,
- Scene *scene,
- DagNode *scenenode,
- bConstraint *con,
- const bConstraintTypeInfo *cti,
- DagNode *node,
- bool is_data)
-{
- if (!ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK,
- CONSTRAINT_TYPE_CAMERASOLVER,
- CONSTRAINT_TYPE_OBJECTSOLVER))
- {
- return false;
- }
- bool depends_on_camera = false;
- if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
- bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data;
- if ((data->clip || data->flag & FOLLOWTRACK_ACTIVECLIP) && data->track[0]) {
- depends_on_camera = true;
- }
- if (data->depth_ob != NULL) {
- DagNode *node2 = dag_get_node(dag, data->depth_ob);
- dag_add_relation(dag,
- node2, node,
- (is_data) ? (DAG_RL_DATA_DATA | DAG_RL_OB_DATA)
- : (DAG_RL_DATA_OB | DAG_RL_OB_OB),
- cti->name);
- }
- }
- else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
- depends_on_camera = true;
- }
- if (depends_on_camera && scene->camera != NULL) {
- DagNode *node2 = dag_get_node(dag, scene->camera);
- dag_add_relation(dag,
- node2, node,
- (is_data) ? (DAG_RL_DATA_DATA | DAG_RL_OB_DATA)
- : (DAG_RL_DATA_OB | DAG_RL_OB_OB),
- cti->name);
- }
- dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
- return true;
-}
-
-static void build_dag_object(DagForest *dag, DagNode *scenenode, 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) {
- continue;
- }
-
- if (build_deg_tracking_constraints(dag, scene, scenenode, con, cti, node, true)) {
- /* pass */
- }
- else if (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,
- CONSTRAINT_TYPE_SHRINKWRAP))
- {
- 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;
- ModifierUpdateDepsgraphContext ctx = {
- .scene = scene,
- .object = ob,
-
- .forest = dag,
- .obNode = node,
- };
- for (md = ob->modifiers.first; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
-
- if (mti->updateDepgraph) mti->updateDepgraph(md, &ctx);
- }
- }
- 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");
- }
- }
- }
- }
-
- /* rigidbody force fields */
- if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_LATTICE)) {
- if (ob->rigidbody_object && scene->rigidbody_world) {
- dag_add_forcefield_relations(dag, scene, ob, node, scene->rigidbody_world->effector_weights, true, 0, "Force Field");
- }
- }
-
- /* 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(G.main, G.main->eval_ctx, 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, 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;
-
- 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");
- }
- }
-
- if (part->type != PART_HAIR) {
- /* Actual code uses get_collider_cache */
- dag_add_collision_relations(dag, scene, ob, node, part->collision_group, ob->lay, eModifierType_Collision, NULL, true, "Particle Collision");
- }
- else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) {
- /* Hair uses cloth simulation, i.e. get_collision_objects */
- dag_add_collision_relations(dag, scene, ob, node, psys->clmd->coll_parms->group, ob->lay | scene->lay, eModifierType_Collision, NULL, true, "Hair Collision");
- }
-
- dag_add_forcefield_relations(dag, scene, ob, node, part->effector_weights, part->type == PART_HAIR, 0, "Particle Force Field");
-
- 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 (build_deg_tracking_constraints(dag, scene, scenenode, con, cti, node, false)) {
- 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 if (cti->type == CONSTRAINT_TYPE_SHRINKWRAP) {
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name);
- }
- 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, 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, sce, ob, mask);
- if (ob->proxy)
- build_dag_object(dag, scenenode, 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, sce, ob, mask);
- if (ob->proxy)
- build_dag_object(dag, scenenode, 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;
- }
- 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;
- }
- }
-
- /* newid abused for GroupObject, cleanup. */
- for (ob = bmain->object.first; ob; ob = ob->id.next) {
- ob->id.newid = NULL;
- }
-}
-
-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->recalc & ID_RECALC_ALL) != 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->recalc |= ID_RECALC;
- DAG_id_type_tag(bmain, GS(id->name));
-}
-
-static void lib_id_recalc_data_tag(Main *bmain, ID *id)
-{
- id->recalc |= 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()) {
- DEG_scene_flush_update(bmain, sce);
- 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 (cu->str && cu->vfont) {
- /* Can be in the curve-cache or the curve. */
- if (ob->curve_cache && !BLI_listbase_is_empty(&ob->curve_cache->disp)) {
- /* pass */
- }
- else if (!BLI_listbase_is_empty(&cu->nurb)) {
- /* pass */
- }
- else {
- 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(cb_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->recalc & ID_RECALC_ALL) {
- 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) {
- id->recalc &= ~ID_RECALC_ALL;
-
- /* some ID's contain semi-datablock nodetree */
- ntree = ntreeFromID(id);
- if (ntree)
- ntree->id.recalc &= ~ID_RECALC_ALL;
- }
- }
- }
-
- 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_TAG) {
- 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_ALL;
- 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_ALL;
- 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);
- }
-
- atomic_fetch_and_or_uint8((uint8_t *)&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_and_fetch_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_relations_graphviz(scene->depsgraph, stdout, "Depsgraph");
-}
-
-#endif
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index dea1a3718dd..8d49521831f 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
@@ -48,13 +49,14 @@
#include "BLI_utildefines.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_object.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_mball_tessellate.h"
+#include "BKE_mesh.h"
#include "BKE_curve.h"
#include "BKE_key.h"
#include "BKE_anim.h"
@@ -64,6 +66,9 @@
#include "BLI_sys_types.h" // for intptr_t support
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
static void boundbox_displist_object(Object *ob);
void BKE_displist_elem_free(DispList *dl)
@@ -680,17 +685,17 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis
* - first point left, last point right
* - based on subdivided points in original curve, not on points in taper curve (still)
*/
-static float displist_calc_taper(Scene *scene, Object *taperobj, float fac)
+static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, float fac)
{
DispList *dl;
if (taperobj == NULL || taperobj->type != OB_CURVE)
return 1.0;
- dl = taperobj->curve_cache ? taperobj->curve_cache->disp.first : NULL;
+ dl = taperobj->runtime.curve_cache ? taperobj->runtime.curve_cache->disp.first : NULL;
if (dl == NULL) {
- BKE_displist_make_curveTypes(scene, taperobj, 0);
- dl = taperobj->curve_cache->disp.first;
+ BKE_displist_make_curveTypes(depsgraph, scene, taperobj, 0);
+ dl = taperobj->runtime.curve_cache->disp.first;
}
if (dl) {
float minx, dx, *fp;
@@ -720,39 +725,39 @@ static float displist_calc_taper(Scene *scene, Object *taperobj, float fac)
return 1.0;
}
-float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot)
+float BKE_displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *taperobj, int cur, int tot)
{
float fac = ((float)cur) / (float)(tot - 1);
- return displist_calc_taper(scene, taperobj, fac);
+ return displist_calc_taper(depsgraph, scene, taperobj, fac);
}
-void BKE_displist_make_mball(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob)
+void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
if (!ob || ob->type != OB_MBALL)
return;
- if (ob == BKE_mball_basis_find(bmain, eval_ctx, scene, ob)) {
- if (ob->curve_cache) {
- BKE_displist_free(&(ob->curve_cache->disp));
+ if (ob == BKE_mball_basis_find(scene, ob)) {
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&(ob->runtime.curve_cache->disp));
}
else {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
}
- BKE_mball_polygonize(bmain, eval_ctx, scene, ob, &ob->curve_cache->disp);
+ BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp);
BKE_mball_texspace_calc(ob);
- object_deform_mball(ob, &ob->curve_cache->disp);
+ object_deform_mball(ob, &ob->runtime.curve_cache->disp);
/* NOP for MBALLs anyway... */
boundbox_displist_object(ob);
}
}
-void BKE_displist_make_mball_forRender(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
+void BKE_displist_make_mball_forRender(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
- BKE_mball_polygonize(bmain, eval_ctx, scene, ob, dispbase);
+ BKE_mball_polygonize(depsgraph, scene, ob, dispbase);
BKE_mball_texspace_calc(ob);
object_deform_mball(ob, dispbase);
@@ -800,14 +805,15 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob,
return pretessellatePoint;
}
-static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
- const bool for_render, const bool use_render_resolution)
+static void curve_calc_modifiers_pre(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
+ const bool for_render, const bool use_render_resolution)
{
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
ModifierData *pretessellatePoint;
Curve *cu = ob->data;
- int numVerts = 0;
+ int numElems = 0, numVerts = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
ModifierApplyFlag app_flag = 0;
float (*deformedVerts)[3] = NULL;
@@ -825,21 +831,25 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
else
required_mode = eModifierMode_Realtime;
+ const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+
pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
if (editmode)
required_mode |= eModifierMode_Editmode;
if (!editmode) {
- keyVerts = BKE_key_evaluate_object(ob, &numVerts);
+ keyVerts = BKE_key_evaluate_object(ob, &numElems);
if (keyVerts) {
+ BLI_assert(BKE_keyblock_curve_element_count(nurb) == numElems);
+
/* split coords from key data, the latter also includes
* tilts, which is passed through in the modifier stack.
* this is also the reason curves do not use a virtual
* shape key modifier yet. */
deformedVerts = BKE_curve_nurbs_keyVertexCos_get(nurb, keyVerts);
- BLI_assert(BKE_nurbList_verts_count(nurb) == numVerts);
+ numVerts = BKE_nurbList_verts_count(nurb);
}
}
@@ -847,8 +857,6 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!modifier_isEnabled(scene, md, required_mode))
continue;
if (mti->type != eModifierTypeType_OnlyDeform)
@@ -858,7 +866,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, ListBase *nurb,
deformedVerts = BKE_curve_nurbs_vertexCos_get(nurb, &numVerts);
}
- mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, app_flag);
+ mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
if (md == pretessellatePoint)
break;
@@ -910,9 +918,10 @@ static void displist_apply_allverts(ListBase *dispbase, float (*allverts)[3])
}
}
-static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
- ListBase *dispbase, DerivedMesh **r_dm_final,
- const bool for_render, const bool use_render_resolution)
+static void curve_calc_modifiers_post(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *nurb,
+ ListBase *dispbase, Mesh **r_final,
+ const bool for_render, const bool use_render_resolution)
{
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
@@ -920,7 +929,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
Curve *cu = ob->data;
int required_mode = 0, totvert = 0;
const bool editmode = (!for_render && (cu->editnurb || cu->editfont));
- DerivedMesh *dm = NULL, *ndm;
+ Mesh *modified = NULL, *mesh_applied;
float (*vertCos)[3] = NULL;
int useCache = !for_render;
ModifierApplyFlag app_flag = 0;
@@ -932,6 +941,11 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
else
required_mode = eModifierMode_Realtime;
+ const ModifierEvalContext mectx_deform = {depsgraph, ob,
+ editmode ? app_flag | MOD_APPLY_USECACHE : app_flag};
+ const ModifierEvalContext mectx_apply = {depsgraph, ob,
+ useCache ? app_flag | MOD_APPLY_USECACHE : app_flag};
+
pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
if (editmode)
@@ -941,43 +955,34 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
md = pretessellatePoint->next;
}
- if (r_dm_final && *r_dm_final) {
- (*r_dm_final)->release(*r_dm_final);
+ if (r_final && *r_final) {
+ BKE_id_free(NULL, r_final);
}
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- ModifierApplyFlag appf = app_flag;
-
- md->scene = scene;
if (!modifier_isEnabled(scene, md, required_mode))
continue;
if (mti->type == eModifierTypeType_OnlyDeform ||
- (mti->type == eModifierTypeType_DeformOrConstruct && !dm))
+ (mti->type == eModifierTypeType_DeformOrConstruct && !modified))
{
- if (editmode)
- appf |= MOD_APPLY_USECACHE;
- if (dm) {
+ if (modified) {
if (!vertCos) {
- totvert = dm->getNumVerts(dm);
- vertCos = MEM_mallocN(sizeof(*vertCos) * totvert, "dfmv");
- dm->getVertCos(dm, vertCos);
+ vertCos = BKE_mesh_vertexCos_get(modified, &totvert);
}
-
- mti->deformVerts(md, ob, dm, vertCos, totvert, appf);
+ mti->deformVerts(md, &mectx_deform, modified, vertCos, totvert);
}
else {
if (!vertCos) {
vertCos = displist_get_allverts(dispbase, &totvert);
}
-
- mti->deformVerts(md, ob, NULL, vertCos, totvert, appf);
+ mti->deformVerts(md, &mectx_deform, NULL, vertCos, totvert);
}
}
else {
- if (!r_dm_final) {
+ if (!r_final) {
/* makeDisplistCurveTypes could be used for beveling, where derived mesh
* is totally unnecessary, so we could stop modifiers applying
* when we found constructive modifier but derived mesh is unwanted result
@@ -985,13 +990,17 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
break;
}
- if (dm) {
+ if (modified) {
if (vertCos) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
-
- CDDM_apply_vert_coords(dm, vertCos);
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
}
}
else {
@@ -1003,7 +1012,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
curve_to_filledpoly(cu, nurb, dispbase);
}
- dm = CDDM_from_curve_displist(ob, dispbase);
+ modified = BKE_mesh_new_nomain_from_curve_displist(ob, dispbase);
}
if (vertCos) {
@@ -1012,29 +1021,31 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
vertCos = NULL;
}
- if (useCache)
- appf |= MOD_APPLY_USECACHE;
+ mesh_applied = mti->applyModifier(md, &mectx_apply, modified);
- ndm = modwrap_applyModifier(md, ob, dm, appf);
-
- if (ndm) {
+ if (mesh_applied) {
/* Modifier returned a new derived mesh */
- if (dm && dm != ndm) /* Modifier */
- dm->release(dm);
- dm = ndm;
+ if (modified && modified != mesh_applied) /* Modifier */
+ BKE_id_free(NULL, modified);
+ modified = mesh_applied;
}
}
}
if (vertCos) {
- if (dm) {
- DerivedMesh *tdm = CDDM_copy(dm);
- dm->release(dm);
- dm = tdm;
+ if (modified) {
+ Mesh *temp_mesh;
+ BKE_id_copy_ex(NULL, &modified->id, (ID **)&temp_mesh,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_id_free(NULL, modified);
+ modified = temp_mesh;
+
+ BKE_mesh_apply_vert_coords(modified, vertCos);
+ BKE_mesh_calc_normals_mapping_simple(modified);
- CDDM_apply_vert_coords(dm, vertCos);
- CDDM_calc_normals_mapping(dm);
MEM_freeN(vertCos);
}
else {
@@ -1044,23 +1055,27 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *nurb,
}
}
- if (r_dm_final) {
- if (dm) {
+ if (r_final) {
+ if (modified) {
/* see: mesh_calc_modifiers */
- if (dm->getNumTessFaces(dm) == 0) {
- dm->recalcTessellation(dm);
+ if (modified->totface == 0) {
+ BKE_mesh_tessface_calc(modified);
}
/* Even if tessellation is not needed, some modifiers might have modified CD layers
* (like mloopcol or mloopuv), hence we have to update those. */
- else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
- DM_update_tessface_data(dm);
+ else if (modified->runtime.cd_dirty_vert & CD_MASK_TESSLOOPNORMAL) {
+ BKE_mesh_tessface_calc(modified);
}
- if (dm->type == DM_TYPE_CDDM) {
- CDDM_calc_normals_mapping_ex(dm, (dm->dirty & DM_DIRTY_NORMALS) ? false : true);
- }
+ /* XXX2.8(Sybren): make sure the face normals are recalculated as well */
+ BKE_mesh_ensure_normals(modified);
+
+ (*r_final) = modified;
+ }
+ else {
+ (*r_final) = NULL;
}
- (*r_dm_final) = dm;
+
}
}
@@ -1092,13 +1107,15 @@ static void displist_surf_indices(DispList *dl)
}
}
-static DerivedMesh *create_orco_dm(Scene *scene, Object *ob)
+/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
+static DerivedMesh *create_orco_dm(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
DerivedMesh *dm;
ListBase disp = {NULL, NULL};
/* OrcoDM should be created from underformed disp lists */
- BKE_displist_make_curveTypes_forOrco(scene, ob, &disp);
+ BKE_displist_make_curveTypes_forOrco(depsgraph, scene, ob, &disp);
dm = CDDM_from_curve_displist(ob, &disp);
BKE_displist_free(&disp);
@@ -1135,9 +1152,13 @@ static void add_orco_dm(Object *ob, DerivedMesh *dm, DerivedMesh *orcodm)
else
DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, orco);
}
+#endif
-static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
- const bool for_render, const bool use_render_resolution)
+/* XXX2.8(Sybren): unused function; impossible to test after porting to Mesh */
+#ifdef WITH_DERIVEDMESH_DEPRECATED_FUNCS
+static void curve_calc_orcodm(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, DerivedMesh *dm_final,
+ const bool for_render, const bool use_render_resolution)
{
/* this function represents logic of mesh's orcodm calculation
* for displist-based objects
@@ -1158,6 +1179,8 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
else
required_mode = eModifierMode_Realtime;
+ const ModifierEvalContext mectx = {depsgraph, ob, app_flag};
+
pretessellatePoint = curve_get_tessellate_point(scene, ob, use_render_resolution, editmode);
if (editmode)
@@ -1174,7 +1197,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
* This means we can create ORCO DM in advance and assume it's
* never NULL.
*/
- orcodm = create_orco_dm(scene, ob);
+ orcodm = create_orco_dm(depsgraph, scene, ob);
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
@@ -1186,7 +1209,7 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
if (mti->type != eModifierTypeType_Constructive)
continue;
- ndm = modwrap_applyModifier(md, ob, orcodm, app_flag);
+ ndm = modwrap_applyModifier(md, &mectx, orcodm);
if (ndm) {
/* if the modifier returned a new dm, release the old one */
@@ -1202,10 +1225,12 @@ static void curve_calc_orcodm(Scene *scene, Object *ob, DerivedMesh *dm_final,
orcodm->release(orcodm);
}
+#endif
-void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final,
- const bool for_render, const bool for_orco, const bool use_render_resolution)
+void BKE_displist_make_surf(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
+ Mesh **r_final,
+ const bool for_render, const bool for_orco, const bool use_render_resolution)
{
ListBase nubase = {NULL, NULL};
Nurb *nu;
@@ -1222,7 +1247,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
}
if (!for_orco)
- curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution);
+ curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
for (nu = nubase.first; nu; nu = nu->next) {
if ((for_render || nu->hide == 0) && BKE_nurb_check_valid_uv(nu)) {
@@ -1288,8 +1313,8 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
}
if (!for_orco) {
- BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final,
+ BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
+ curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final,
for_render, use_render_resolution);
}
@@ -1515,9 +1540,10 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu,
}
}
-static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final,
- const bool for_render, const bool for_orco, const bool use_render_resolution)
+static void do_makeDispListCurveTypes(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
+ Mesh **r_final,
+ const bool for_render, const bool for_orco, const bool use_render_resolution)
{
Curve *cu = ob->data;
@@ -1525,21 +1551,21 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return;
if (ob->type == OB_SURF) {
- BKE_displist_make_surf(scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution);
+ BKE_displist_make_surf(depsgraph, scene, ob, dispbase, r_final, for_render, for_orco, use_render_resolution);
}
else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
ListBase dlbev;
ListBase nubase = {NULL, NULL};
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
/* We only re-evaluate path if evaluation is not happening for orco.
* If the calculation happens for orco, we should never free data which
* was needed before and only not needed for orco calculation.
*/
if (!for_orco) {
- if (ob->curve_cache->path) free_path(ob->curve_cache->path);
- ob->curve_cache->path = NULL;
+ if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path);
+ ob->runtime.curve_cache->path = NULL;
}
if (ob->type == OB_FONT) {
@@ -1550,12 +1576,12 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
if (!for_orco)
- curve_calc_modifiers_pre(scene, ob, &nubase, for_render, use_render_resolution);
+ curve_calc_modifiers_pre(depsgraph, scene, ob, &nubase, for_render, use_render_resolution);
BKE_curve_bevelList_make(ob, &nubase, for_render != false);
/* If curve has no bevel will return nothing */
- BKE_curve_bevel_make(scene, ob, &dlbev, for_render, use_render_resolution);
+ BKE_curve_bevel_make(depsgraph, scene, ob, &dlbev, for_render, use_render_resolution);
/* no bevel or extrude, and no width correction? */
if (!dlbev.first && cu->width == 1.0f) {
@@ -1563,7 +1589,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
else {
float widfac = cu->width - 1.0f;
- BevList *bl = ob->curve_cache->bev.first;
+ BevList *bl = ob->runtime.curve_cache->bev.first;
Nurb *nu = nubase.first;
for (; bl && nu; bl = bl->next, nu = nu->next) {
@@ -1690,7 +1716,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
taper_fac -= (1.0f - lastblend) / len;
}
- fac = displist_calc_taper(scene, cu->taperobj, taper_fac);
+ fac = displist_calc_taper(depsgraph, scene, cu->taperobj, taper_fac);
}
if (bevp->split_tag) {
@@ -1743,18 +1769,18 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
if (!for_orco) {
if ((cu->flag & CU_PATH) ||
- DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CURVE_PATH)
+ DEG_get_eval_flags_for_id(depsgraph, &ob->id) & DAG_EVAL_NEED_CURVE_PATH)
{
calc_curvepath(ob, &nubase);
}
}
if (!for_orco) {
- BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
- curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution);
+ BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase);
+ curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_final, for_render, use_render_resolution);
}
- if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) {
+ if (cu->flag & CU_DEFORM_FILL && !ob->runtime.mesh_eval) {
curve_to_filledpoly(cu, &nubase, dispbase);
}
@@ -1762,7 +1788,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
}
-void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco)
+void BKE_displist_make_curveTypes(Depsgraph *depsgraph, Scene *scene, Object *ob, const bool for_orco)
{
ListBase *dispbase;
@@ -1774,58 +1800,37 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco)
BKE_object_free_derived_caches(ob);
- if (!ob->curve_cache) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
+ if (!ob->runtime.curve_cache) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
}
- dispbase = &(ob->curve_cache->disp);
+ dispbase = &(ob->runtime.curve_cache->disp);
- do_makeDispListCurveTypes(scene, ob, dispbase, &ob->derivedFinal, 0, for_orco, 0);
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, &ob->runtime.mesh_eval, 0, for_orco, 0);
boundbox_displist_object(ob);
}
-void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final, const bool for_orco,
- const bool use_render_resolution)
+void BKE_displist_make_curveTypes_forRender(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase,
+ Mesh **r_final, const bool for_orco,
+ const bool use_render_resolution)
{
- if (ob->curve_cache == NULL) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
+ if (ob->runtime.curve_cache == NULL) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
- do_makeDispListCurveTypes(scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution);
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, r_final, true, for_orco, use_render_resolution);
}
-void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase)
+void BKE_displist_make_curveTypes_forOrco(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
- if (ob->curve_cache == NULL) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
- }
-
- do_makeDispListCurveTypes(scene, ob, dispbase, NULL, 1, 1, 1);
-}
-
-/* add Orco layer to the displist object which has got derived mesh and return orco */
-float *BKE_displist_make_orco(Scene *scene, Object *ob, DerivedMesh *dm_final,
- const bool for_render,
- const bool use_render_resolution)
-{
- float *orco;
-
- if (dm_final == NULL)
- dm_final = ob->derivedFinal;
-
- if (!dm_final->getVertDataArray(dm_final, CD_ORCO)) {
- curve_calc_orcodm(scene, ob, dm_final, for_render, use_render_resolution);
- }
-
- orco = dm_final->getVertDataArray(dm_final, CD_ORCO);
-
- if (orco) {
- orco = MEM_dupallocN(orco);
+ if (ob->runtime.curve_cache == NULL) {
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
- return orco;
+ do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, NULL, 1, 1, 1);
}
void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3])
@@ -1863,14 +1868,14 @@ static void boundbox_displist_object(Object *ob)
if (ob->bb == NULL)
ob->bb = MEM_callocN(sizeof(BoundBox), "boundbox");
- if (ob->derivedFinal) {
- DM_set_object_boundbox(ob, ob->derivedFinal);
+ if (ob->runtime.mesh_eval) {
+ BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
}
else {
float min[3], max[3];
INIT_MINMAX(min, max);
- BKE_displist_minmax(&ob->curve_cache->disp, min, max);
+ BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
BKE_boundbox_init_from_minmax(ob->bb, min, max);
ob->bb->flag &= ~BOUNDBOX_DIRTY;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 661c802d64e..8c39b50101b 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -41,9 +41,9 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_dynamicpaint_types.h"
-#include "DNA_group_types.h" /*GroupObject*/
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -55,26 +55,31 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h" /* bvh tree */
+#include "BKE_collection.h"
+#include "BKE_collision.h"
#include "BKE_colorband.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_constraint.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_dynamicpaint.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
/* for image output */
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -246,7 +251,7 @@ static int dynamicPaint_surfaceNumOfPoints(DynamicPaintSurface *surface)
return 0; /* not supported atm */
}
else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- return (surface->canvas->dm) ? surface->canvas->dm->getNumVerts(surface->canvas->dm) : 0;
+ return (surface->canvas->mesh) ? surface->canvas->mesh->totvert : 0;
}
return 0;
@@ -487,42 +492,17 @@ static void scene_setSubframe(Scene *scene, float subframe)
scene->r.subframe = subframe;
}
-static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene)
+static int surface_getBrushFlags(DynamicPaintSurface *surface, Depsgraph *depsgraph)
{
- Base *base = NULL;
- GroupObject *go = NULL;
- Object *brushObj = NULL;
- ModifierData *md = NULL;
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
int flags = 0;
- if (surface->brush_group)
- go = surface->brush_group->gobject.first;
- else
- base = scene->base.first;
-
- while (base || go) {
- brushObj = NULL;
-
- /* select object */
- if (surface->brush_group) {
- if (go->ob)
- brushObj = go->ob;
- }
- else {
- brushObj = base->object;
- }
-
- if (surface->brush_group)
- go = go->next;
- else
- base = base->next;
-
- if (!brushObj) {
- continue;
- }
+ for (int i = 0; i < numobjects; i++) {
+ Object *brushObj = objects[i];
- md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
@@ -535,12 +515,9 @@ static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scen
}
}
- return flags;
-}
+ BKE_collision_objects_free(objects);
-static int brush_usesMaterial(const DynamicPaintBrushSettings *brush, const Scene *scene)
-{
- return ((brush->flags & MOD_DPAINT_USE_MATERIAL) && (!BKE_scene_use_new_shading_nodes(scene)));
+ return flags;
}
/* check whether two bounds intersect */
@@ -837,9 +814,10 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface)
void dynamicPaint_freeBrush(struct DynamicPaintModifierData *pmd)
{
if (pmd->brush) {
- if (pmd->brush->dm)
- pmd->brush->dm->release(pmd->brush->dm);
- pmd->brush->dm = NULL;
+ if (pmd->brush->mesh) {
+ BKE_id_free(NULL, pmd->brush->mesh);
+ }
+ pmd->brush->mesh = NULL;
if (pmd->brush->paint_ramp)
MEM_freeN(pmd->brush->paint_ramp);
@@ -966,10 +944,11 @@ void dynamicPaint_freeCanvas(DynamicPaintModifierData *pmd)
surface = next_surface;
}
- /* free dm copy */
- if (pmd->canvas->dm)
- pmd->canvas->dm->release(pmd->canvas->dm);
- pmd->canvas->dm = NULL;
+ /* free mesh copy */
+ if (pmd->canvas->mesh) {
+ BKE_id_free(NULL, pmd->canvas->mesh);
+ }
+ pmd->canvas->mesh = NULL;
MEM_freeN(pmd->canvas);
pmd->canvas = NULL;
@@ -1081,7 +1060,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
if (!canvas)
return false;
canvas->pmd = pmd;
- canvas->dm = NULL;
+ canvas->mesh = NULL;
/* Create one surface */
if (!dynamicPaint_createNewSurface(canvas, scene))
@@ -1103,7 +1082,6 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
brush->flags = MOD_DPAINT_ABS_ALPHA | MOD_DPAINT_RAMP_ALPHA;
brush->collision = MOD_DPAINT_COL_VOLUME;
- brush->mat = NULL;
brush->r = 0.15f;
brush->g = 0.4f;
brush->b = 0.8f;
@@ -1122,7 +1100,7 @@ bool dynamicPaint_createType(struct DynamicPaintModifierData *pmd, int type, str
brush->smudge_strength = 0.3f;
brush->max_velocity = 1.0f;
- brush->dm = NULL;
+ brush->mesh = NULL;
/* Paint proximity falloff colorramp. */
{
@@ -1243,7 +1221,6 @@ void dynamicPaint_Modifier_copy(const struct DynamicPaintModifierData *pmd, stru
t_brush->flags = brush->flags;
t_brush->collision = brush->collision;
- t_brush->mat = brush->mat;
t_brush->r = brush->r;
t_brush->g = brush->g;
t_brush->b = brush->b;
@@ -1311,7 +1288,7 @@ static bool surface_usesAdjData(DynamicPaintSurface *surface)
static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const bool force_init)
{
PaintSurfaceData *sData = surface->data;
- DerivedMesh *dm = surface->canvas->dm;
+ Mesh *mesh = surface->canvas->mesh;
PaintAdjData *ad;
int *temp_data;
int neigh_points = 0;
@@ -1321,7 +1298,7 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
/* For vertex format, neighbors are connected by edges */
- neigh_points = 2 * dm->getNumEdges(dm);
+ neigh_points = 2 * mesh->totedge;
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
neigh_points = sData->total_points * 8;
@@ -1357,11 +1334,11 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b
int n_pos;
/* For vertex format, count every vertex that is connected by an edge */
- int numOfEdges = dm->getNumEdges(dm);
- int numOfPolys = dm->getNumPolys(dm);
- struct MEdge *edge = dm->getEdgeArray(dm);
- struct MPoly *mpoly = dm->getPolyArray(dm);
- struct MLoop *mloop = dm->getLoopArray(dm);
+ int numOfEdges = mesh->totedge;
+ int numOfPolys = mesh->totpoly;
+ struct MEdge *edge = mesh->medge;
+ struct MPoly *mpoly = mesh->mpoly;
+ struct MLoop *mloop = mesh->mloop;
/* count number of edges per vertex */
for (i = 0; i < numOfEdges; i++) {
@@ -1545,7 +1522,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
{
PaintSurfaceData *sData = surface->data;
PaintPoint *pPoint = (PaintPoint *)sData->type_data;
- DerivedMesh *dm = surface->canvas->dm;
+ Mesh *mesh = surface->canvas->mesh;
int i;
const bool scene_color_manage = BKE_scene_check_color_management_enabled(scene);
@@ -1566,9 +1543,9 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
else if (surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
Tex *tex = surface->init_texture;
- const MLoop *mloop = dm->getLoopArray(dm);
- const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
+ const MLoop *mloop = mesh->mloop;
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ const int tottri = BKE_mesh_runtime_looptri_len(mesh);
const MLoopUV *mloopuv = NULL;
char uvname[MAX_CUSTOMDATA_LAYER_NAME];
@@ -1577,8 +1554,8 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
return;
/* get uv map */
- CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->init_layername, uvname);
- mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->init_layername, uvname);
+ mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
if (!mloopuv)
return;
@@ -1621,9 +1598,9 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
/* for vertex surface, just copy colors from mcol */
if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
- const MLoop *mloop = dm->getLoopArray(dm);
- const int totloop = dm->getNumLoops(dm);
- const MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
+ const MLoop *mloop = mesh->mloop;
+ const int totloop = mesh->totloop;
+ const MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername);
if (!col)
return;
@@ -1632,8 +1609,8 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
- const MLoopTri *mlooptri = dm->getLoopTriArray(dm);
- MLoopCol *col = CustomData_get_layer_named(&dm->loopData, CD_MLOOPCOL, surface->init_layername);
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ MLoopCol *col = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPCOL, surface->init_layername);
if (!col)
return;
@@ -1755,7 +1732,7 @@ static void dynamic_paint_apply_surface_displace_cb(
}
/* apply displacing vertex surface to the derived mesh */
-static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, DerivedMesh *result)
+static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh *result)
{
PaintSurfaceData *sData = surface->data;
@@ -1764,7 +1741,7 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Deri
/* displace paint */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
- MVert *mvert = result->getVertArray(result);
+ MVert *mvert = result->mvert;
DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
ParallelRangeSettings settings;
@@ -1882,10 +1859,10 @@ static void dynamic_paint_apply_surface_wave_cb(
/*
* Apply canvas data to the object derived mesh
*/
-static DerivedMesh *dynamicPaint_Modifier_apply(
- DynamicPaintModifierData *pmd, Object *ob, DerivedMesh *dm)
+static Mesh *dynamicPaint_Modifier_apply(
+ DynamicPaintModifierData *pmd, Object *ob, Mesh *mesh)
{
- DerivedMesh *result = CDDM_copy(dm);
+ Mesh *result = BKE_mesh_copy_for_eval(mesh, false);
if (pmd->canvas && !(pmd->canvas->flags & MOD_DPAINT_BAKING)) {
@@ -1905,10 +1882,10 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
/* vertex color paint */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
- MLoop *mloop = CDDM_get_loops(result);
- const int totloop = result->numLoopData;
- MPoly *mpoly = CDDM_get_polys(result);
- const int totpoly = result->numPolyData;
+ MLoop *mloop = result->mloop;
+ const int totloop = result->totloop;
+ MPoly *mpoly = result->mpoly;
+ const int totpoly = result->totpoly;
/* paint is stored on dry and wet layers, so mix final color first */
float (*fcolor)[4] = MEM_callocN(sizeof(*fcolor) * sData->total_points, "Temp paint color");
@@ -1926,28 +1903,28 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
}
/* paint layer */
- MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name);
+ MLoopCol *mloopcol = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name);
/* if output layer is lost from a constructive modifier, re-add it */
if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) {
mloopcol = CustomData_add_layer_named(
- &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
+ &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name);
}
/* wet layer */
- MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name2);
+ MLoopCol *mloopcol_wet = CustomData_get_layer_named(&result->ldata, CD_MLOOPCOL, surface->output_name2);
/* if output layer is lost from a constructive modifier, re-add it */
if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) {
mloopcol_wet = CustomData_add_layer_named(
- &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
+ &result->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2);
}
/* Save preview results to weight layer to be able to share same drawing methods */
MLoopCol *mloopcol_preview = NULL;
if (surface->flags & MOD_DPAINT_PREVIEW) {
- mloopcol_preview = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL);
+ mloopcol_preview = CustomData_get_layer(&result->ldata, CD_PREVIEW_MLOOPCOL);
if (!mloopcol_preview) {
mloopcol_preview = CustomData_add_layer(
- &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
+ &result->ldata, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop);
}
}
@@ -1972,12 +1949,12 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
MEM_freeN(fcolor);
/* Mark tessellated CD layers as dirty. */
- result->dirty |= DM_DIRTY_TESS_CDLAYERS;
+ //result->dirty |= DM_DIRTY_TESS_CDLAYERS;
}
/* vertex group paint */
else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
int defgrp_index = defgroup_name_index(ob, surface->output_name);
- MDeformVert *dvert = result->getVertDataArray(result, CD_MDEFORMVERT);
+ MDeformVert *dvert = CustomData_get_layer(&result->vdata, CD_MDEFORMVERT);
float *weight = (float *)sData->type_data;
/* viewport preview */
@@ -1985,12 +1962,13 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
/* Save preview results to weight layer to be
* able to share same drawing methods.
* Note this func also sets DM_DIRTY_TESS_CDLAYERS flag! */
- DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
+ //TODO port this function
+ //DM_update_weight_mcol(ob, result, 0, weight, 0, NULL);
}
/* apply weights into a vertex group, if doesn't exists add a new layer */
if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) {
- dvert = CustomData_add_layer(&result->vertData, CD_MDEFORMVERT, CD_CALLOC,
+ dvert = CustomData_add_layer(&result->vdata, CD_MDEFORMVERT, CD_CALLOC,
NULL, sData->total_points);
}
if (defgrp_index != -1 && dvert) {
@@ -2014,7 +1992,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
}
/* wave simulation */
else if (surface->type == MOD_DPAINT_SURFACE_T_WAVE) {
- MVert *mvert = result->getVertArray(result);
+ MVert *mvert = result->mvert;
DynamicPaintModifierApplyData data = {.surface = surface, .mvert = mvert};
ParallelRangeSettings settings;
@@ -2038,14 +2016,15 @@ static DerivedMesh *dynamicPaint_Modifier_apply(
}
if (update_normals) {
- result->dirty |= DM_DIRTY_NORMALS;
+ //result->dirty |= DM_DIRTY_NORMALS;
}
}
- /* make a copy of dm to use as brush data */
+ /* make a copy of mesh to use as brush data */
if (pmd->brush) {
- if (pmd->brush->dm)
- pmd->brush->dm->release(pmd->brush->dm);
- pmd->brush->dm = CDDM_copy(result);
+ if (pmd->brush->mesh) {
+ BKE_id_free(NULL, pmd->brush->mesh);
+ }
+ pmd->brush->mesh = BKE_mesh_copy_for_eval(result, false);
}
return result;
@@ -2060,27 +2039,28 @@ void dynamicPaint_cacheUpdateFrames(DynamicPaintSurface *surface)
}
}
-static void canvas_copyDerivedMesh(DynamicPaintCanvasSettings *canvas, DerivedMesh *dm)
+static void canvas_copyMesh(DynamicPaintCanvasSettings *canvas, Mesh *mesh)
{
- if (canvas->dm) {
- canvas->dm->release(canvas->dm);
+ if (canvas->mesh) {
+ BKE_id_free(NULL, canvas->mesh);
}
- canvas->dm = CDDM_copy(dm);
+ canvas->mesh = BKE_mesh_copy_for_eval(mesh, false);
}
/*
* Updates derived mesh copy and processes dynamic paint step / caches.
*/
static void dynamicPaint_frameUpdate(
- Main *bmain, EvaluationContext *eval_ctx, DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+ DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, Mesh *mesh)
{
if (pmd->canvas) {
DynamicPaintCanvasSettings *canvas = pmd->canvas;
DynamicPaintSurface *surface = canvas->surfaces.first;
/* update derived mesh copy */
- canvas_copyDerivedMesh(canvas, dm);
+ canvas_copyMesh(canvas, mesh);
/* in case image sequence baking, stop here */
if (canvas->flags & MOD_DPAINT_BAKING)
@@ -2136,14 +2116,14 @@ static void dynamicPaint_frameUpdate(
else if (can_simulate) {
/* calculate surface frame */
canvas->flags |= MOD_DPAINT_BAKING;
- dynamicPaint_calculateFrame(bmain, eval_ctx, surface, scene, ob, current_frame);
+ dynamicPaint_calculateFrame(surface, depsgraph, scene, ob, current_frame);
canvas->flags &= ~MOD_DPAINT_BAKING;
- /* restore canvas derivedmesh if required */
+ /* restore canvas mesh if required */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE &&
surface->flags & MOD_DPAINT_DISP_INCREMENTAL && surface->next)
{
- canvas_copyDerivedMesh(canvas, dm);
+ canvas_copyMesh(canvas, mesh);
}
BKE_ptcache_validate(cache, surface->current_frame);
@@ -2155,26 +2135,27 @@ static void dynamicPaint_frameUpdate(
}
/* Modifier call. Processes dynamic paint modifier step. */
-DerivedMesh *dynamicPaint_Modifier_do(Main *bmain,
- EvaluationContext *eval_ctx, DynamicPaintModifierData *pmd, Scene *scene, Object *ob, DerivedMesh *dm)
+Mesh *dynamicPaint_Modifier_do(
+ DynamicPaintModifierData *pmd, struct Depsgraph *depsgraph, Scene *scene,
+ Object *ob, Mesh *mesh)
{
if (pmd->canvas) {
- DerivedMesh *ret;
+ Mesh *ret;
/* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(bmain, eval_ctx, pmd, scene, ob, dm);
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
/* Return output mesh */
- ret = dynamicPaint_Modifier_apply(pmd, ob, dm);
+ ret = dynamicPaint_Modifier_apply(pmd, ob, mesh);
return ret;
}
else {
/* Update canvas data for a new frame */
- dynamicPaint_frameUpdate(bmain, eval_ctx, pmd, scene, ob, dm);
+ dynamicPaint_frameUpdate(pmd, depsgraph, scene, ob, mesh);
/* Return output mesh */
- return dynamicPaint_Modifier_apply(pmd, ob, dm);
+ return dynamicPaint_Modifier_apply(pmd, ob, mesh);
}
}
@@ -2776,7 +2757,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
PaintSurfaceData *sData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
- DerivedMesh *dm = canvas->dm;
+ Mesh *mesh = canvas->mesh;
PaintUVPoint *tempPoints = NULL;
Vec3f *tempWeights = NULL;
@@ -2790,19 +2771,19 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
*progress = 0.0f;
*do_update = true;
- if (!dm)
+ if (!mesh)
return setError(canvas, N_("Canvas mesh not updated"));
if (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ)
return setError(canvas, N_("Cannot bake non-'image sequence' formats"));
- mloop = dm->getLoopArray(dm);
- mlooptri = dm->getLoopTriArray(dm);
- const int tottri = dm->getNumLoopTri(dm);
+ mloop = mesh->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);;
+ const int tottri = BKE_mesh_runtime_looptri_len(mesh);
/* get uv map */
- if (CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
- CustomData_validate_layer_name(&dm->loopData, CD_MLOOPUV, surface->uvlayer_name, uvname);
- mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, uvname);
+ if (CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) {
+ CustomData_validate_layer_name(&mesh->ldata, CD_MLOOPUV, surface->uvlayer_name, uvname);
+ mloopuv = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvname);
}
/* Check for validity */
@@ -2928,7 +2909,7 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo
BKE_mesh_vert_looptri_map_create(
&vert_to_looptri_map, &vert_to_looptri_map_mem,
- dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm));
+ mesh->mvert, mesh->totvert, mlooptri, tottri, mloop, mesh->totloop);
int total_border = 0;
@@ -3341,91 +3322,6 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
}
-/***************************** Material / Texture Sampling ******************************/
-
-/* stores a copy of required materials to allow doing adjustments
- * without interfering the render/preview */
-typedef struct BrushMaterials {
- Material *mat;
- Material **ob_mats;
- int tot;
-} BrushMaterials;
-
-/* Initialize materials for brush object:
- * Calculates inverse matrices for linked objects, updates
- * volume caches etc. */
-static void dynamicPaint_updateBrushMaterials(Object *brushOb, Material *ui_mat, Scene *scene, BrushMaterials *bMats)
-{
- /* Calculate inverse transformation matrix
- * for this object */
- invert_m4_m4(brushOb->imat, brushOb->obmat);
- copy_m4_m4(brushOb->imat_ren, brushOb->imat);
-
- /* Now process every material linked to this brush object */
- if ((ui_mat == NULL) && brushOb->mat && brushOb->totcol) {
- int i, tot = (*give_totcolp(brushOb));
-
- /* allocate material pointer array */
- if (tot) {
- bMats->ob_mats = MEM_callocN(sizeof(Material *) * (tot), "BrushMaterials");
- for (i = 0; i < tot; i++) {
- bMats->ob_mats[i] = RE_sample_material_init(give_current_material(brushOb, (i + 1)), scene);
- }
- }
- bMats->tot = tot;
- }
- else {
- bMats->mat = RE_sample_material_init(ui_mat, scene);
- }
-}
-
-/* free all data allocated by dynamicPaint_updateBrushMaterials() */
-static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats)
-{
- /* Now process every material linked to this brush object */
- if (bMats->ob_mats) {
- int i;
- for (i = 0; i < bMats->tot; i++) {
- RE_sample_material_free(bMats->ob_mats[i]);
- }
- MEM_freeN(bMats->ob_mats);
- }
- else if (bMats->mat) {
- RE_sample_material_free(bMats->mat);
- }
-}
-
-/*
- * Get material diffuse color and alpha (including linked textures) in given coordinates
- */
-static void dynamicPaint_doMaterialTex(
- const BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb,
- const float volume_co[3], const float surface_co[3],
- int triIndex, DerivedMesh *orcoDm)
-{
- Material *mat = bMats->mat;
-
- const MLoopTri *mlooptri = orcoDm->getLoopTriArray(orcoDm);
- const MPoly *mpoly = orcoDm->getPolyArray(orcoDm);
-
- /* If no material defined, use the one assigned to the mesh face */
- if (mat == NULL) {
- if (bMats->ob_mats) {
- int mat_nr = mpoly[mlooptri[triIndex].poly].mat_nr;
- if (mat_nr >= (*give_totcolp(brushOb)))
- return;
- mat = bMats->ob_mats[mat_nr];
- if (mat == NULL)
- return; /* No material assigned */
- }
- else {
- return;
- }
- }
- RE_sample_material_color(mat, color, alpha, volume_co, surface_co, triIndex, orcoDm, brushOb);
-}
-
-
/***************************** Ray / Nearest Point Utils ******************************/
@@ -3746,11 +3642,11 @@ static void dynamic_paint_brush_velocity_compute_cb(
}
static void dynamicPaint_brushMeshCalculateVelocity(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene,
+ Depsgraph *depsgraph, Scene *scene,
Object *ob, DynamicPaintBrushSettings *brush, Vec3f **brushVel, float timescale)
{
float prev_obmat[4][4];
- DerivedMesh *dm_p, *dm_c;
+ Mesh *mesh_p, *mesh_c;
MVert *mvert_p, *mvert_c;
int numOfVerts_p, numOfVerts_c;
@@ -3764,26 +3660,26 @@ static void dynamicPaint_brushMeshCalculateVelocity(
prev_fra = cur_fra - 1;
}
- /* previous frame dm */
+ /* previous frame mesh */
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- dm_p = CDDM_copy(brush->dm);
- numOfVerts_p = dm_p->getNumVerts(dm_p);
- mvert_p = dm_p->getVertArray(dm_p);
+ depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ mesh_p = BKE_mesh_copy_for_eval(brush->mesh, false);
+ numOfVerts_p = mesh_p->totvert;
+ mvert_p = mesh_p->mvert;
copy_m4_m4(prev_obmat, ob->obmat);
- /* current frame dm */
+ /* current frame mesh */
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
- dm_c = brush->dm;
- numOfVerts_c = dm_c->getNumVerts(dm_c);
- mvert_c = dm_p->getVertArray(dm_c);
+ depsgraph, scene, ob, true, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ mesh_c = brush->mesh;
+ numOfVerts_c = mesh_c->totvert;
+ mvert_c = mesh_c->mvert;
(*brushVel) = (struct Vec3f *) MEM_mallocN(numOfVerts_c * sizeof(Vec3f), "Dynamic Paint brush velocity");
if (!(*brushVel))
@@ -3807,12 +3703,12 @@ static void dynamicPaint_brushMeshCalculateVelocity(
dynamic_paint_brush_velocity_compute_cb,
&settings);
- dm_p->release(dm_p);
+ BKE_id_free(NULL, mesh_p);
}
/* calculate velocity for object center point */
static void dynamicPaint_brushObjectCalculateVelocity(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, Vec3f *brushVel, float timescale)
{
float prev_obmat[4][4];
float cur_loc[3] = {0.0f}, prev_loc[3] = {0.0f};
@@ -3827,18 +3723,18 @@ static void dynamicPaint_brushObjectCalculateVelocity(
prev_fra = cur_fra - 1;
}
- /* previous frame dm */
+ /* previous frame mesh */
scene->r.cfra = prev_fra;
scene->r.subframe = prev_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
copy_m4_m4(prev_obmat, ob->obmat);
- /* current frame dm */
+ /* current frame mesh */
scene->r.cfra = cur_fra;
scene->r.subframe = cur_sfra;
BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
+ depsgraph, scene, ob, false, SUBFRAME_RECURSION, BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
/* calculate speed */
mul_m4_v3(prev_obmat, prev_loc);
@@ -3852,12 +3748,11 @@ typedef struct DynamicPaintPaintData {
const DynamicPaintSurface *surface;
const DynamicPaintBrushSettings *brush;
Object *brushOb;
- const BrushMaterials *bMats;
const Scene *scene;
const float timescale;
const int c_index;
- DerivedMesh *dm;
+ Mesh *mesh;
const MVert *mvert;
const MLoop *mloop;
const MLoopTri *mlooptri;
@@ -3889,14 +3784,10 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
VolumeGrid *grid = bData->grid;
const DynamicPaintBrushSettings *brush = data->brush;
- Object *brushOb = data->brushOb;
- const BrushMaterials *bMats = data->bMats;
- const Scene *scene = data->scene;
const float timescale = data->timescale;
const int c_index = data->c_index;
- DerivedMesh *dm = data->dm;
const MVert *mvert = data->mvert;
const MLoop *mloop = data->mloop;
const MLoopTri *mlooptri = data->mlooptri;
@@ -4156,13 +4047,6 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
sampleColor[1] = brush->g;
sampleColor[2] = brush->b;
- /* Get material+textures color on hit point if required */
- if (brush_usesMaterial(brush, scene)) {
- dynamicPaint_doMaterialTex(bMats, sampleColor, &alpha_factor, brushOb,
- bData->realCoord[bData->s_pos[index] + ss].v,
- hitCoord, hitTri, dm);
- }
-
/* Sample proximity colorband if required */
if ((hit_found == HIT_PROXIMITY) &&
(brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP))
@@ -4210,27 +4094,24 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex(
}
}
-static int dynamicPaint_paintMesh(Main *bmain,
- EvaluationContext *eval_ctx,
- DynamicPaintSurface *surface,
+static int dynamicPaint_paintMesh(Depsgraph *depsgraph, DynamicPaintSurface *surface,
DynamicPaintBrushSettings *brush,
Object *brushOb,
- BrushMaterials *bMats,
Scene *scene,
float timescale)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- DerivedMesh *dm = NULL;
+ Mesh *mesh = NULL;
Vec3f *brushVelocity = NULL;
MVert *mvert = NULL;
const MLoopTri *mlooptri = NULL;
const MLoop *mloop = NULL;
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushMeshCalculateVelocity(bmain, eval_ctx, scene, brushOb, brush, &brushVelocity, timescale);
+ dynamicPaint_brushMeshCalculateVelocity(depsgraph, scene, brushOb, brush, &brushVelocity, timescale);
- if (!brush->dm)
+ if (!brush->mesh)
return 0;
{
@@ -4242,11 +4123,11 @@ static int dynamicPaint_paintMesh(Main *bmain,
Bounds3D mesh_bb = {{0}};
VolumeGrid *grid = bData->grid;
- dm = CDDM_copy(brush->dm);
- mvert = dm->getVertArray(dm);
- mlooptri = dm->getLoopTriArray(dm);
- mloop = dm->getLoopArray(dm);
- numOfVerts = dm->getNumVerts(dm);
+ mesh = BKE_mesh_copy_for_eval(brush->mesh, false);
+ mvert = mesh->mvert;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ mloop = mesh->mloop;
+ numOfVerts = mesh->totvert;
/* Transform collider vertices to global space
* (Faster than transforming per surface point
@@ -4277,7 +4158,7 @@ static int dynamicPaint_paintMesh(Main *bmain,
/* check bounding box collision */
if (grid && meshBrush_boundsIntersect(&grid->grid_bounds, &mesh_bb, brush, brush_radius)) {
/* Build a bvh tree from transformed vertices */
- if (bvhtree_from_mesh_get(&treeData, dm, BVHTREE_FROM_LOOPTRI, 4)) {
+ if (BKE_bvhtree_from_mesh_get(&treeData, mesh, BVHTREE_FROM_LOOPTRI, 4)) {
int c_index;
int total_cells = grid->dim[0] * grid->dim[1] * grid->dim[2];
@@ -4293,9 +4174,9 @@ static int dynamicPaint_paintMesh(Main *bmain,
/* loop through cell points and process brush */
DynamicPaintPaintData data = {
.surface = surface,
- .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .brush = brush, .brushOb = brushOb,
.scene = scene, .timescale = timescale, .c_index = c_index,
- .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
+ .mesh = mesh, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri,
.brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity,
.treeData = &treeData
};
@@ -4311,7 +4192,7 @@ static int dynamicPaint_paintMesh(Main *bmain,
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
- dm->release(dm);
+ BKE_id_free(NULL, mesh);
}
@@ -4618,13 +4499,9 @@ static void dynamic_paint_paint_single_point_cb_ex(
const PaintBakeData *bData = sData->bData;
const DynamicPaintBrushSettings *brush = data->brush;
- Object *brushOb = data->brushOb;
- const BrushMaterials *bMats = data->bMats;
- const Scene *scene = data->scene;
const float timescale = data->timescale;
- const MVert *mvert = data->mvert;
const float brush_radius = data->brush_radius;
const Vec3f *brushVelocity = data->brushVelocity;
@@ -4653,17 +4530,6 @@ static void dynamic_paint_paint_single_point_cb_ex(
float depth = 0.0f;
float velocity_val = 0.0f;
- /* material */
- if (brush_usesMaterial(brush, scene)) {
- float alpha_factor = 1.0f;
- float hit_coord[3];
- /* use dummy coord of first vertex */
- mul_v3_m4v3(hit_coord, brushOb->obmat, mvert[0].co);
-
- dynamicPaint_doMaterialTex(bMats, paintColor, &alpha_factor, brushOb,
- bData->realCoord[bData->s_pos[index]].v, hit_coord, 0, brush->dm);
- }
-
/* color ramp */
if (brush->proximity_falloff == MOD_DPAINT_PRFALL_RAMP &&
BKE_colorband_evaluate(brush->paint_ramp, (1.0f - strength), colorband))
@@ -4701,11 +4567,9 @@ static void dynamic_paint_paint_single_point_cb_ex(
paintColor[2] = colorband[2];
}
else {
- if (!brush_usesMaterial(brush, scene)) {
- paintColor[0] = brush->r;
- paintColor[1] = brush->g;
- paintColor[2] = brush->b;
- }
+ paintColor[0] = brush->r;
+ paintColor[1] = brush->g;
+ paintColor[2] = brush->b;
}
}
else if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
@@ -4718,24 +4582,24 @@ static void dynamic_paint_paint_single_point_cb_ex(
}
static int dynamicPaint_paintSinglePoint(
- Main *bmain, EvaluationContext *eval_ctx, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
- Object *brushOb, BrushMaterials *bMats, Scene *scene, float timescale)
+ Depsgraph *depsgraph, DynamicPaintSurface *surface, float *pointCoord, DynamicPaintBrushSettings *brush,
+ Object *brushOb, Scene *scene, float timescale)
{
PaintSurfaceData *sData = surface->data;
float brush_radius = brush->paint_distance * surface->radius_scale;
Vec3f brushVel;
if (brush->flags & MOD_DPAINT_USES_VELOCITY)
- dynamicPaint_brushObjectCalculateVelocity(bmain, eval_ctx, scene, brushOb, &brushVel, timescale);
+ dynamicPaint_brushObjectCalculateVelocity(depsgraph, scene, brushOb, &brushVel, timescale);
- const MVert *mvert = brush->dm->getVertArray(brush->dm);
+ const MVert *mvert = brush->mesh->mvert;
/*
* Loop through every surface point
*/
DynamicPaintPaintData data = {
.surface = surface,
- .brush = brush, .brushOb = brushOb, .bMats = bMats,
+ .brush = brush, .brushOb = brushOb,
.scene = scene, .timescale = timescale,
.mvert = mvert,
.brush_radius = brush_radius, .brushVelocity = &brushVel,
@@ -5019,7 +4883,7 @@ static void dynamic_paint_prepare_effect_cb(
EffectedPoint epoint;
pd_point_from_loc(scene, realCoord[bData->s_pos[index]].v, vel, index, &epoint);
epoint.vel_to_sec = 1.0f;
- pdDoEffectors(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
+ BKE_effectors_apply(effectors, NULL, surface->effector_weights, &epoint, forc, NULL);
}
/* if global gravity is enabled, add it too */
@@ -5048,7 +4912,7 @@ static void dynamic_paint_prepare_effect_cb(
}
static int dynamicPaint_prepareEffectStep(
- DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
+ struct Depsgraph *depsgraph, DynamicPaintSurface *surface, Scene *scene, Object *ob, float **force, float timescale)
{
double average_force = 0.0f;
float shrink_speed = 0.0f, spread_speed = 0.0f;
@@ -5059,7 +4923,7 @@ static int dynamicPaint_prepareEffectStep(
/* Init force data if required */
if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) {
- ListBase *effectors = pdInitEffectors(scene, ob, NULL, surface->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, surface->effector_weights);
/* allocate memory for force data (dir vector + strength) */
*force = MEM_mallocN(sData->total_points * 4 * sizeof(float), "PaintEffectForces");
@@ -5083,7 +4947,7 @@ static int dynamicPaint_prepareEffectStep(
}
average_force /= sData->total_points;
}
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
}
/* Get number of required steps using average point distance
@@ -5747,10 +5611,10 @@ static bool dynamicPaint_surfaceHasMoved(DynamicPaintSurface *surface, Object *o
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- DerivedMesh *dm = surface->canvas->dm;
- MVert *mvert = dm->getVertArray(dm);
+ Mesh *mesh = surface->canvas->mesh;
+ MVert *mvert = mesh->mvert;
- int numOfVerts = dm->getNumVerts(dm);
+ int numOfVerts = mesh->totvert;
int i;
if (!bData->prev_verts)
@@ -5891,19 +5755,19 @@ static void dynamic_paint_generate_bake_data_cb(
}
}
-static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Scene *scene, Object *ob)
+static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, Depsgraph *depsgraph, Object *ob)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
- DerivedMesh *dm = surface->canvas->dm;
+ Mesh *mesh = surface->canvas->mesh;
int index;
bool new_bdata = false;
const bool do_velocity_data = ((surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) ||
- (surface_getBrushFlags(surface, scene) & BRUSH_USES_VELOCITY));
+ (surface_getBrushFlags(surface, depsgraph) & BRUSH_USES_VELOCITY));
const bool do_accel_data = (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) != 0;
- int canvasNumOfVerts = dm->getNumVerts(dm);
- MVert *mvert = dm->getVertArray(dm);
+ int canvasNumOfVerts = mesh->totvert;
+ MVert *mvert = mesh->mvert;
Vec3f *canvas_verts;
if (bData) {
@@ -6017,12 +5881,13 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce
* Do Dynamic Paint step. Paints scene brush objects of current state/frame to the surface.
*/
static int dynamicPaint_doStep(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene,
+ Depsgraph *depsgraph, Scene *scene,
Object *ob, DynamicPaintSurface *surface, float timescale, float subframe)
{
PaintSurfaceData *sData = surface->data;
PaintBakeData *bData = sData->bData;
DynamicPaintCanvasSettings *canvas = surface->canvas;
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
int ret = 1;
if (sData->total_points < 1)
@@ -6043,50 +5908,23 @@ static int dynamicPaint_doStep(
* Loop through surface's target paint objects and do painting
*/
{
- Base *base = NULL;
- GroupObject *go = NULL;
- Object *brushObj = NULL;
- ModifierData *md = NULL;
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, NULL, surface->brush_group, &numobjects, eModifierType_DynamicPaint);
/* backup current scene frame */
int scene_frame = scene->r.cfra;
float scene_subframe = scene->r.subframe;
- /* either from group or from all objects */
- if (surface->brush_group)
- go = surface->brush_group->gobject.first;
- else
- base = scene->base.first;
-
- while (base || go) {
- brushObj = NULL;
- /* select object */
- if (surface->brush_group) {
- if (go->ob)
- brushObj = go->ob;
- }
- else
- brushObj = base->object;
-
- /* next item */
- if (surface->brush_group)
- go = go->next;
- else
- base = base->next;
-
- if (!brushObj) {
- /* skip item */
- continue;
- }
+ for (int i = 0; i < numobjects; i++) {
+ Object *brushObj = objects[i];
/* check if target has an active dp modifier */
- md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
+ ModifierData *md = modifiers_findByType(brushObj, eModifierType_DynamicPaint);
if (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) {
DynamicPaintModifierData *pmd2 = (DynamicPaintModifierData *)md;
/* make sure we're dealing with a brush */
if (pmd2->brush) {
DynamicPaintBrushSettings *brush = pmd2->brush;
- BrushMaterials bMats = {NULL};
/* calculate brush speed vectors if required */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT && brush->flags & MOD_DPAINT_DO_SMUDGE) {
@@ -6101,44 +5939,35 @@ static int dynamicPaint_doStep(
/* update object data on this subframe */
if (subframe) {
scene_setSubframe(scene, subframe);
- BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
- /* Prepare materials if required */
- if (brush_usesMaterial(brush, scene))
- dynamicPaint_updateBrushMaterials(brushObj, brush->mat, scene, &bMats);
+
/* Apply brush on the surface depending on it's collision type */
- /* Particle brush: */
- if (brush->collision == MOD_DPAINT_COL_PSYS) {
- if (brush->psys && brush->psys->part &&
- ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
- psys_check_enabled(brushObj, brush->psys, G.is_rendering))
- {
- /* Paint a particle system */
- BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt,
- BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
- dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
- }
+ if (brush->psys && brush->psys->part &&
+ ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) &&
+ psys_check_enabled(brushObj, brush->psys, for_render))
+ {
+ /* Paint a particle system */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &brush->psys->part->id, brush->psys->part->adt,
+ BKE_scene_frame_get(scene), ADT_RECALC_ANIM);
+ dynamicPaint_paintParticles(surface, brush->psys, brush, timescale);
}
/* Object center distance: */
- else if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
- dynamicPaint_paintSinglePoint(
- bmain, eval_ctx, surface, brushObj->loc, brush, brushObj, &bMats, scene, timescale);
+ if (brush->collision == MOD_DPAINT_COL_POINT && brushObj != ob) {
+ dynamicPaint_paintSinglePoint(depsgraph, surface, brushObj->loc, brush, brushObj, scene, timescale);
}
/* Mesh volume/proximity: */
else if (brushObj != ob) {
- dynamicPaint_paintMesh(bmain, eval_ctx, surface, brush, brushObj, &bMats, scene, timescale);
+ dynamicPaint_paintMesh(depsgraph, surface, brush, brushObj, scene, timescale);
}
- /* free temp material data */
- if (brush_usesMaterial(brush, scene))
- dynamicPaint_freeBrushMaterials(&bMats);
/* reset object to it's original state */
if (subframe) {
scene->r.cfra = scene_frame;
scene->r.subframe = scene_subframe;
- BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, brushObj, true, SUBFRAME_RECURSION,
+ BKE_object_modifier_update_subframe(depsgraph, scene, brushObj, true, SUBFRAME_RECURSION,
BKE_scene_frame_get(scene), eModifierType_DynamicPaint);
}
@@ -6152,6 +5981,8 @@ static int dynamicPaint_doStep(
}
}
}
+
+ BKE_collision_objects_free(objects);
}
/* surfaces operations that use adjacency data */
@@ -6173,7 +6004,7 @@ static int dynamicPaint_doStep(
return setError(canvas, N_("Not enough free memory"));
/* Prepare effects and get number of required steps */
- steps = dynamicPaint_prepareEffectStep(surface, scene, ob, &force, timescale);
+ steps = dynamicPaint_prepareEffectStep(depsgraph, surface, scene, ob, &force, timescale);
for (s = 0; s < steps; s++) {
dynamicPaint_doEffectStep(surface, force, prevPoint, timescale, (float)steps);
}
@@ -6198,16 +6029,17 @@ static int dynamicPaint_doStep(
* Calculate a single frame and included subframes for surface
*/
int dynamicPaint_calculateFrame(
- Main *bmain, EvaluationContext *eval_ctx, DynamicPaintSurface *surface, Scene *scene, Object *cObject, int frame)
+ DynamicPaintSurface *surface, struct Depsgraph *depsgraph,
+ Scene *scene, Object *cObject, int frame)
{
float timescale = 1.0f;
/* apply previous displace on derivedmesh if incremental surface */
if (surface->flags & MOD_DPAINT_DISP_INCREMENTAL)
- dynamicPaint_applySurfaceDisplace(surface, surface->canvas->dm);
+ dynamicPaint_applySurfaceDisplace(surface, surface->canvas->mesh);
/* update bake data */
- dynamicPaint_generateBakeData(surface, scene, cObject);
+ dynamicPaint_generateBakeData(surface, depsgraph, cObject);
/* don't do substeps for first frame */
if (surface->substeps && (frame != surface->start_frame)) {
@@ -6216,10 +6048,10 @@ int dynamicPaint_calculateFrame(
for (st = 1; st <= surface->substeps; st++) {
float subframe = ((float) st) / (surface->substeps + 1);
- if (!dynamicPaint_doStep(bmain, eval_ctx, scene, cObject, surface, timescale, subframe))
+ if (!dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, subframe))
return 0;
}
}
- return dynamicPaint_doStep(bmain, eval_ctx, scene, cObject, surface, timescale, 0.0f);
+ return dynamicPaint_doStep(depsgraph, scene, cObject, surface, timescale, 0.0f);
}
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index db9ce6c9b7d..e6873e66c91 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -49,2290 +49,20 @@
#include "BLI_task.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
#include "BKE_editmesh.h"
#include "BKE_editmesh_bvh.h"
+#include "BKE_editmesh_cache.h"
+#include "BKE_editmesh_tangent.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "MEM_guardedalloc.h"
-#include "GPU_glew.h"
-#include "GPU_buffers.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
-static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4]);
-
-typedef struct EditDerivedBMesh {
- DerivedMesh dm;
-
- BMEditMesh *em;
-
- /** when set, \a vertexNos, polyNos are lazy initialized */
- const float (*vertexCos)[3];
-
- /** lazy initialize (when \a vertexCos is set) */
- float const (*vertexNos)[3];
- float const (*polyNos)[3];
- /** also lazy init but dont depend on \a vertexCos */
- const float (*polyCos)[3];
-} EditDerivedBMesh;
-
-/* -------------------------------------------------------------------- */
-/* Lazy initialize datastructures */
-
-static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm);
-
-static void emDM_ensureVertNormals(EditDerivedBMesh *bmdm)
-{
- if (bmdm->vertexCos && (bmdm->vertexNos == NULL)) {
-
- BMesh *bm = bmdm->em->bm;
- const float (*vertexCos)[3], (*polyNos)[3];
- float (*vertexNos)[3];
-
- /* calculate vertex normals from poly normals */
- emDM_ensurePolyNormals(bmdm);
-
- BM_mesh_elem_index_ensure(bm, BM_FACE);
-
- polyNos = bmdm->polyNos;
- vertexCos = bmdm->vertexCos;
- vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__);
-
- BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos);
-
- bmdm->vertexNos = (const float (*)[3])vertexNos;
- }
-}
-
-static void emDM_ensurePolyNormals(EditDerivedBMesh *bmdm)
-{
- if (bmdm->vertexCos && (bmdm->polyNos == NULL)) {
- BMesh *bm = bmdm->em->bm;
- const float (*vertexCos)[3];
- float (*polyNos)[3];
-
- BMFace *efa;
- BMIter fiter;
- int i;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__);
-
- vertexCos = bmdm->vertexCos;
-
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_elem_index_set(efa, i); /* set_inline */
- BM_face_calc_normal_vcos(bm, efa, polyNos[i], vertexCos);
- }
- bm->elem_index_dirty &= ~BM_FACE;
-
- bmdm->polyNos = (const float (*)[3])polyNos;
- }
-}
-
-static void emDM_ensurePolyCenters(EditDerivedBMesh *bmdm)
-{
- if (bmdm->polyCos == NULL) {
- BMesh *bm = bmdm->em->bm;
- float (*polyCos)[3];
-
- BMFace *efa;
- BMIter fiter;
- int i;
-
- polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__);
-
- if (bmdm->vertexCos) {
- const float (*vertexCos)[3];
- vertexCos = bmdm->vertexCos;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_face_calc_center_mean_vcos(bm, efa, polyCos[i], vertexCos);
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
- BM_face_calc_center_mean(efa, polyCos[i]);
- }
- }
-
- bmdm->polyCos = (const float (*)[3])polyCos;
- }
-}
-
-static void emDM_calcNormals(DerivedMesh *dm)
-{
- /* Nothing to do: normals are already calculated and stored on the
- * BMVerts and BMFaces */
- dm->dirty &= ~DM_DIRTY_NORMALS;
-}
-
-static void emDM_calcLoopNormalsSpaceArray(
- DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr);
-
-static void emDM_calcLoopNormals(DerivedMesh *dm, const bool use_split_normals, const float split_angle)
-{
- emDM_calcLoopNormalsSpaceArray(dm, use_split_normals, split_angle, NULL);
-}
-
-/* #define DEBUG_CLNORS */
-
-static void emDM_calcLoopNormalsSpaceArray(
- DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- const float (*vertexCos)[3], (*vertexNos)[3], (*polyNos)[3];
- float (*loopNos)[3];
- short (*clnors_data)[2];
- int cd_loop_clnors_offset;
-
- /* calculate loop normals from poly and vertex normals */
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- dm->dirty &= ~DM_DIRTY_NORMALS;
-
- vertexCos = bmdm->vertexCos;
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- loopNos = dm->getLoopDataArray(dm, CD_NORMAL);
- if (!loopNos) {
- DM_add_loop_layer(dm, CD_NORMAL, CD_CALLOC, NULL);
- loopNos = dm->getLoopDataArray(dm, CD_NORMAL);
- }
-
- /* We can have both, give priority to dm's data, and fallback to bm's ones. */
- clnors_data = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL);
- cd_loop_clnors_offset = clnors_data ? -1 : CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
-
- BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, use_split_normals, split_angle, loopNos,
- r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
-#ifdef DEBUG_CLNORS
- if (r_lnors_spacearr) {
- int i;
- for (i = 0; i < numLoops; i++) {
- if (r_lnors_spacearr->lspacearr[i]->ref_alpha != 0.0f) {
- LinkNode *loops = r_lnors_spacearr->lspacearr[i]->loops;
- printf("Loop %d uses lnor space %p:\n", i, r_lnors_spacearr->lspacearr[i]);
- print_v3("\tfinal lnor:", loopNos[i]);
- print_v3("\tauto lnor:", r_lnors_spacearr->lspacearr[i]->vec_lnor);
- print_v3("\tref_vec:", r_lnors_spacearr->lspacearr[i]->vec_ref);
- printf("\talpha: %f\n\tbeta: %f\n\tloops: %p\n", r_lnors_spacearr->lspacearr[i]->ref_alpha,
- r_lnors_spacearr->lspacearr[i]->ref_beta, r_lnors_spacearr->lspacearr[i]->loops);
- printf("\t\t(shared with loops");
- while (loops) {
- printf(" %d", POINTER_AS_INT(loops->link));
- loops = loops->next;
- }
- printf(")\n");
- }
- else {
- printf("Loop %d has no lnor space\n", i);
- }
- }
- }
-#endif
-}
-
-
-/** \name Tangent Space Calculation
- * \{ */
-
-/* Necessary complexity to handle looptri's as quads for correct tangents */
-#define USE_LOOPTRI_DETECT_QUADS
-
-typedef struct {
- const float (*precomputedFaceNormals)[3];
- const float (*precomputedLoopNormals)[3];
- const BMLoop *(*looptris)[3];
- int cd_loop_uv_offset; /* texture coordinates */
- const float (*orco)[3];
- float (*tangent)[4]; /* destination */
- int numTessFaces;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- /* map from 'fake' face index to looptri,
- * quads will point to the first looptri of the quad */
- const int *face_as_quad_map;
- int num_face_as_quad_map;
-#endif
-
-} SGLSLEditMeshToTangent;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
-/* seems weak but only used on quads */
-static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
-{
- const BMLoop *l = BM_FACE_FIRST_LOOP(f);
- while (vert_index--) {
- l = l->next;
- }
- return l;
-}
-#endif
-
-/* interface */
-#include "mikktspace.h"
-
-static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
-{
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- return pMesh->num_face_as_quad_map;
-#else
- return pMesh->numTessFaces;
-#endif
-}
-
-static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
-{
-#ifdef USE_LOOPTRI_DETECT_QUADS
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- if (pMesh->face_as_quad_map) {
- const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- return 4;
- }
- }
- return 3;
-#else
- UNUSED_VARS(pContext, face_num);
- return 3;
-#endif
-}
-
-static void emdm_ts_GetPosition(
- const SMikkTSpaceContext *pContext, float r_co[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
- const float *co;
-
-finally:
- co = l->v->co;
- copy_v3_v3(r_co, co);
-}
-
-static void emdm_ts_GetTextureCoordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
-finally:
- if (pMesh->cd_loop_uv_offset != -1) {
- const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
- copy_v2_v2(r_uv, uv);
- }
- else {
- const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
- map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
- }
-}
-
-static void emdm_ts_GetNormal(
- const SMikkTSpaceContext *pContext, float r_no[3],
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
-finally:
- if (pMesh->precomputedLoopNormals) {
- copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
- }
- else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
- if (pMesh->precomputedFaceNormals) {
- copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
- }
- else {
- copy_v3_v3(r_no, l->f->no);
- }
- }
- else {
- copy_v3_v3(r_no, l->v->no);
- }
-}
-
-static void emdm_ts_SetTSpace(
- const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
- const int face_num, const int vert_index)
-{
- //assert(vert_index >= 0 && vert_index < 4);
- SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
- const BMLoop **lt;
- const BMLoop *l;
-
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (pMesh->face_as_quad_map) {
- lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
- if (lt[0]->f->len == 4) {
- l = bm_loop_at_face_index(lt[0]->f, vert_index);
- goto finally;
- }
- /* fall through to regular triangle */
- }
- else {
- lt = pMesh->looptris[face_num];
- }
-#else
- lt = pMesh->looptris[face_num];
-#endif
- l = lt[vert_index];
-
- float *pRes;
-
-finally:
- pRes = pMesh->tangent[BM_elem_index_get(l)];
- copy_v3_v3(pRes, fvTangent);
- pRes[3] = fSign;
-}
-
-static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
-{
- struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
- /* new computation method */
- {
- SMikkTSpaceContext sContext = {NULL};
- SMikkTSpaceInterface sInterface = {NULL};
- sContext.m_pUserData = mesh2tangent;
- sContext.m_pInterface = &sInterface;
- sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
- sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
- sInterface.m_getPosition = emdm_ts_GetPosition;
- sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
- sInterface.m_getNormal = emdm_ts_GetNormal;
- sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
- /* 0 if failed */
- genTangSpaceDefault(&sContext);
- }
-}
-
-/**
- * \see #DM_calc_loop_tangents, same logic but used arrays instead of #BMesh data.
- *
- * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
- * This is done because #CD_TANGENT is cache data used only for drawing.
- */
-
-static void emDM_calc_loop_tangents(
- DerivedMesh *dm, bool calc_active_tangent,
- const char (*tangent_names)[MAX_NAME], int tangent_names_count)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = bmdm->em->bm;
-
- int act_uv_n = -1;
- int ren_uv_n = -1;
- bool calc_act = false;
- bool calc_ren = false;
- char act_uv_name[MAX_NAME];
- char ren_uv_name[MAX_NAME];
- short tangent_mask = 0;
-
- DM_calc_loop_tangents_step_0(
- &bm->ldata, calc_active_tangent, tangent_names, tangent_names_count,
- &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
-
- if ((dm->tangent_mask | tangent_mask) != dm->tangent_mask) {
- for (int i = 0; i < tangent_names_count; i++)
- if (tangent_names[i][0])
- DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, tangent_names[i]);
- if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, "") == -1)
- CustomData_add_layer_named(&dm->loopData, CD_TANGENT, CD_CALLOC, NULL, dm->numLoopData, "");
- if (calc_act && act_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, act_uv_name);
- if (calc_ren && ren_uv_name[0])
- DM_add_named_tangent_layer_for_uv(&bm->ldata, &dm->loopData, dm->numLoopData, ren_uv_name);
- int totface = em->tottri;
-#ifdef USE_LOOPTRI_DETECT_QUADS
- int num_face_as_quad_map;
- int *face_as_quad_map = NULL;
-
- /* map faces to quads */
- if (bmdm->em->tottri != bm->totface) {
- /* over alloc, since we dont know how many ngon or quads we have */
-
- /* map fake face index to looptri */
- face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
- int i, j;
- for (i = 0, j = 0; j < totface; i++, j++) {
- face_as_quad_map[i] = j;
- /* step over all quads */
- if (em->looptris[j][0]->f->len == 4) {
- j++; /* skips the nest looptri */
- }
- }
- num_face_as_quad_map = i;
- }
- else {
- num_face_as_quad_map = totface;
- }
-#endif
- /* Calculation */
- {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- TaskPool *task_pool;
- task_pool = BLI_task_pool_create(scheduler, NULL);
-
- dm->tangent_mask = 0;
- /* Calculate tangent layers */
- SGLSLEditMeshToTangent data_array[MAX_MTFACE];
- int index = 0;
- int n = 0;
- CustomData_update_typemap(&dm->loopData);
- const int tangent_layer_num = CustomData_number_of_layers(&dm->loopData, CD_TANGENT);
- for (n = 0; n < tangent_layer_num; n++) {
- index = CustomData_get_layer_index_n(&dm->loopData, CD_TANGENT, n);
- BLI_assert(n < MAX_MTFACE);
- SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
- mesh2tangent->numTessFaces = em->tottri;
-#ifdef USE_LOOPTRI_DETECT_QUADS
- mesh2tangent->face_as_quad_map = face_as_quad_map;
- mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
-#endif
- mesh2tangent->precomputedFaceNormals = bmdm->polyNos; /* dm->getPolyDataArray(dm, CD_NORMAL) */
- /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
- * have to check this is valid...
- */
- mesh2tangent->precomputedLoopNormals = CustomData_get_layer(&dm->loopData, CD_NORMAL);
- mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
-
- /* needed for indexing loop-tangents */
- int htype_index = BM_LOOP;
- if (mesh2tangent->cd_loop_uv_offset == -1) {
- mesh2tangent->orco = dm->getVertDataArray(dm, CD_ORCO);
- if (!mesh2tangent->orco)
- continue;
- /* needed for orco lookups */
- htype_index |= BM_VERT;
- dm->tangent_mask |= DM_TANGENT_MASK_ORCO;
- }
- else {
- /* Fill the resulting tangent_mask */
- int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, dm->loopData.layers[index].name);
- int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
- BLI_assert(uv_ind != -1 && uv_start != -1);
- BLI_assert(uv_ind - uv_start < MAX_MTFACE);
- dm->tangent_mask |= 1 << (uv_ind - uv_start);
- }
-
- if (mesh2tangent->precomputedFaceNormals) {
- /* needed for face normal lookups */
- htype_index |= BM_FACE;
- }
- BM_mesh_elem_index_ensure(bm, htype_index);
-
- mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
- mesh2tangent->tangent = dm->loopData.layers[index].data;
-
- BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
- }
-
- BLI_assert(dm->tangent_mask == tangent_mask);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- }
-#ifdef USE_LOOPTRI_DETECT_QUADS
- if (face_as_quad_map) {
- MEM_freeN(face_as_quad_map);
- }
-#undef USE_LOOPTRI_DETECT_QUADS
-#endif
- }
-
- /* Update active layer index */
- int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
- if (act_uv_index >= 0) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
- CustomData_set_layer_active_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
-
- /* Update render layer index */
- int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
- if (ren_uv_index >= 0) {
- int tan_index = CustomData_get_named_layer_index(&dm->loopData, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
- CustomData_set_layer_render_index(&dm->loopData, CD_TANGENT, tan_index);
- } /* else tangent has been built from orco */
-}
-
-/** \} */
-
-
-static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))
-{
- /* do nothing */
-}
-
-static void emDM_recalcLoopTri(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMLoop *(*looptris)[3] = bmdm->em->looptris;
- MLoopTri *mlooptri;
- const int tottri = bmdm->em->tottri;
- int i;
-
- DM_ensure_looptri_data(dm);
- mlooptri = dm->looptris.array_wip;
-
- BLI_assert(tottri == 0 || mlooptri != NULL);
- BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num);
- BLI_assert(tottri == dm->looptris.num);
-
- BM_mesh_elem_index_ensure(bmdm->em->bm, BM_FACE | BM_LOOP);
-
- for (i = 0; i < tottri; i++) {
- BMLoop **ltri = looptris[i];
- MLoopTri *lt = &mlooptri[i];
-
- ARRAY_SET_ITEMS(
- lt->tri,
- BM_elem_index_get(ltri[0]),
- BM_elem_index_get(ltri[1]),
- BM_elem_index_get(ltri[2]));
- lt->poly = BM_elem_index_get(ltri[0]->f);
- }
-
- BLI_assert(dm->looptris.array == NULL);
- atomic_cas_ptr((void **)&dm->looptris.array, dm->looptris.array, dm->looptris.array_wip);
- dm->looptris.array_wip = NULL;
-}
-
-static void emDM_foreachMappedVert(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
- void *userData,
- DMForeachFlag flag)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *eve;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
-
- if (flag & DM_FOREACH_USE_NORMAL) {
- emDM_ensureVertNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- }
- else {
- vertexNos = NULL;
- }
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- const float *no = (flag & DM_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL;
- func(userData, i, vertexCos[i], no, NULL);
- }
- }
- else {
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- const float *no = (flag & DM_FOREACH_USE_NORMAL) ? eve->no : NULL;
- func(userData, i, eve->co, no, NULL);
- }
- }
-}
-static void emDM_foreachMappedEdge(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *eed;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- func(userData, i,
- bmdm->vertexCos[BM_elem_index_get(eed->v1)],
- bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
- }
- }
- else {
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- func(userData, i, eed->v1->co, eed->v2->co);
- }
- }
-}
-
-static void emDM_drawMappedEdges(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *eed;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]);
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
- }
- }
- glEnd();
- }
- else {
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- glVertex3fv(eed->v1->co);
- glVertex3fv(eed->v2->co);
- }
- }
- glEnd();
- }
-}
-static void emDM_drawEdges(
- DerivedMesh *dm,
- bool UNUSED(drawLooseEdges),
- bool UNUSED(drawAllEdges))
-{
- emDM_drawMappedEdges(dm, NULL, NULL);
-}
-
-static void emDM_drawMappedEdgesInterp(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetDrawInterpOptions setDrawInterpOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *eed;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- setDrawInterpOptions(userData, i, 0.0);
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v1)]);
- setDrawInterpOptions(userData, i, 1.0);
- glVertex3fv(bmdm->vertexCos[BM_elem_index_get(eed->v2)]);
- }
- }
- glEnd();
- }
- else {
- glBegin(GL_LINES);
- BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
- if (!setDrawOptions || (setDrawOptions(userData, i) != DM_DRAW_OPTION_SKIP)) {
- setDrawInterpOptions(userData, i, 0.0);
- glVertex3fv(eed->v1->co);
- setDrawInterpOptions(userData, i, 1.0);
- glVertex3fv(eed->v2->co);
- }
- }
- glEnd();
- }
-}
-
-static void emDM_drawUVEdges(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMFace *efa;
- BMIter iter;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- if (UNLIKELY(cd_loop_uv_offset == -1)) {
- return;
- }
-
- glBegin(GL_LINES);
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- const float *uv, *uv_prev;
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
- continue;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter->prev, cd_loop_uv_offset))->uv;
- do {
- uv = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- glVertex2fv(uv);
- glVertex2fv(uv_prev);
- uv_prev = uv;
- } while ((l_iter = l_iter->next) != l_first);
- }
- glEnd();
-}
-
-static void emDM_foreachMappedLoop(
- DerivedMesh *dm,
- void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
- void *userData,
- DMForeachFlag flag)
-{
- /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
- * return loop data from bmesh itself. */
- const float (*lnors)[3] = (flag & DM_FOREACH_USE_NORMAL) ? DM_get_loop_data_layer(dm, CD_NORMAL) : NULL;
-
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMFace *efa;
- BMIter iter;
-
- const float (*vertexCos)[3] = bmdm->vertexCos;
- int f_idx;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, f_idx) {
- BMLoop *l_iter, *l_first;
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const BMVert *eve = l_iter->v;
- const int v_idx = BM_elem_index_get(eve);
- const float *no = lnors ? *lnors++ : NULL;
- func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no);
- } while ((l_iter = l_iter->next) != l_first);
- }
-}
-
-static void emDM_foreachMappedFaceCenter(
- DerivedMesh *dm,
- void (*func)(void *userData, int index, const float co[3], const float no[3]),
- void *userData,
- DMForeachFlag flag)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- const float (*polyNos)[3];
- const float (*polyCos)[3];
- BMFace *efa;
- BMIter iter;
- int i;
-
- emDM_ensurePolyCenters(bmdm);
- polyCos = bmdm->polyCos; /* always set */
-
- if (flag & DM_FOREACH_USE_NORMAL) {
- emDM_ensurePolyNormals(bmdm);
- polyNos = bmdm->polyNos; /* maybe NULL */
- }
- else {
- polyNos = NULL;
- }
-
- if (polyNos) {
- BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
- const float *no = polyNos[i];
- func(userData, i, polyCos[i], no);
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
- const float *no = (flag & DM_FOREACH_USE_NORMAL) ? efa->no : NULL;
- func(userData, i, polyCos[i], no);
- }
- }
-}
-
-static void emDM_drawMappedFaces(
- DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- /* currently unused -- each original face is handled separately */
- DMCompareDrawOptions UNUSED(compareDrawOptions),
- void *userData,
- DMDrawFlag flag)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- BMFace *efa;
- struct BMLoop *(*looptris)[3] = bmdm->em->looptris;
- const int tottri = bmdm->em->tottri;
- DMDrawOption draw_option;
- int i;
- const int skip_normals = !(flag & DM_DRAW_NEED_NORMALS);
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */;
- unsigned char(*color_vert_array)[4] = em->derivedVertColor;
- unsigned char(*color_face_array)[4] = em->derivedFaceColor;
- bool has_vcol_preview = (color_vert_array != NULL) && !skip_normals;
- bool has_fcol_preview = (color_face_array != NULL) && !skip_normals;
- bool has_vcol_any = has_vcol_preview;
-
- /* GL_ZERO is used to detect if drawing has started or not */
- GLenum poly_prev = GL_ZERO;
- GLenum shade_prev = GL_ZERO;
- DMDrawOption draw_option_prev = DM_DRAW_OPTION_SKIP;
-
- /* call again below is ok */
- if (has_vcol_preview) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
- if (has_fcol_preview) {
- BM_mesh_elem_index_ensure(bm, BM_FACE);
- }
- if (has_vcol_preview || has_fcol_preview) {
- flag |= DM_DRAW_ALWAYS_SMOOTH;
- /* weak, this logic should really be moved higher up */
- setMaterial = NULL;
- }
-
- if (bmdm->vertexCos) {
- short prev_mat_nr = -1;
-
- /* add direct access */
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
-
- if (skip_normals) {
- vertexNos = NULL;
- polyNos = NULL;
- }
- else {
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
- }
-
- BM_mesh_elem_index_ensure(bm, lnors ? BM_VERT | BM_FACE | BM_LOOP : BM_VERT | BM_FACE);
-
- for (i = 0; i < tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
- drawSmooth = lnors || ((flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : BM_elem_flag_test(efa, BM_ELEM_SMOOTH));
-
- draw_option = (!setDrawOptions ?
- DM_DRAW_OPTION_NORMAL :
- setDrawOptions(userData, BM_elem_index_get(efa)));
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
-
- if (draw_option_prev != draw_option) {
- if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- draw_option_prev = draw_option;
- }
-
-
- if (efa->mat_nr != prev_mat_nr) {
- if (setMaterial) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- setMaterial(efa->mat_nr + 1, NULL);
- }
- prev_mat_nr = efa->mat_nr;
- }
-
- if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
-
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
-
- if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
- else if (has_fcol_preview) glColor3ubv((const GLubyte *)&(color_face_array[BM_elem_index_get(efa)]));
- if (skip_normals) {
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- const GLenum shade_type = drawSmooth ? GL_SMOOTH : GL_FLAT;
- if (shade_type != shade_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glShadeModel((shade_prev = shade_type)); /* same as below but switch shading */
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
-
- if (!drawSmooth) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- }
- }
- }
- }
- else {
- short prev_mat_nr = -1;
-
- BM_mesh_elem_index_ensure(bm, lnors ? BM_FACE | BM_LOOP : BM_FACE);
-
- for (i = 0; i < tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
- drawSmooth = lnors || ((flag & DM_DRAW_ALWAYS_SMOOTH) ? 1 : BM_elem_flag_test(efa, BM_ELEM_SMOOTH));
-
- draw_option = (setDrawOptions ?
- setDrawOptions(userData, BM_elem_index_get(efa)) :
- DM_DRAW_OPTION_NORMAL);
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- const GLenum poly_type = GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
-
- if (draw_option_prev != draw_option) {
- if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- draw_option_prev = draw_option;
- }
-
- if (efa->mat_nr != prev_mat_nr) {
- if (setMaterial) {
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- setMaterial(efa->mat_nr + 1, NULL);
- }
- prev_mat_nr = efa->mat_nr;
- }
-
- if (draw_option == DM_DRAW_OPTION_STIPPLE) { /* enabled with stipple */
-
- if (poly_prev != GL_ZERO) glEnd();
- poly_prev = GL_ZERO; /* force glBegin */
-
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
-
- if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
- else if (has_fcol_preview) glColor3ubv((const GLubyte *)&(color_face_array[BM_elem_index_get(efa)]));
-
- if (skip_normals) {
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- const GLenum shade_type = drawSmooth ? GL_SMOOTH : GL_FLAT;
- if (shade_type != shade_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glShadeModel((shade_prev = shade_type)); /* same as below but switch shading */
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
- if (poly_type != poly_prev) {
- if (poly_prev != GL_ZERO) glEnd();
- glBegin((poly_prev = poly_type)); /* BMesh: will always be GL_TRIANGLES */
- }
-
- if (!drawSmooth) {
- glNormal3fv(efa->no);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(ltri[0]->v->no);
- glVertex3fv(ltri[0]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(ltri[1]->v->no);
- glVertex3fv(ltri[1]->v->co);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(ltri[2]->v->no);
- glVertex3fv(ltri[2]->v->co);
- }
- }
- }
- }
- }
-
- /* if non zero we know a face was rendered */
- if (poly_prev != GL_ZERO) glEnd();
-
- if (draw_option_prev == DM_DRAW_OPTION_STIPPLE) {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
-
- if (shade_prev == GL_FLAT) {
- glShadeModel(GL_SMOOTH);
- }
-}
-
-static void bmdm_get_tri_uv(BMLoop *ltri[3], MLoopUV *luv[3], const int cd_loop_uv_offset)
-{
- luv[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_uv_offset);
- luv[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_uv_offset);
- luv[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_uv_offset);
-}
-
-static void bmdm_get_tri_col(BMLoop *ltri[3], MLoopCol *lcol[3], const int cd_loop_color_offset)
-{
- lcol[0] = BM_ELEM_CD_GET_VOID_P(ltri[0], cd_loop_color_offset);
- lcol[1] = BM_ELEM_CD_GET_VOID_P(ltri[1], cd_loop_color_offset);
- lcol[2] = BM_ELEM_CD_GET_VOID_P(ltri[2], cd_loop_color_offset);
-}
-
-static void bmdm_get_tri_colpreview(BMLoop *ls[3], MLoopCol *lcol[3], unsigned char(*color_vert_array)[4])
-{
- lcol[0] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[0]->v)];
- lcol[1] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[1]->v)];
- lcol[2] = (MLoopCol *)color_vert_array[BM_elem_index_get(ls[2]->v)];
-}
-
-static void emDM_drawFacesTex_common(
- DerivedMesh *dm,
- DMSetDrawOptionsTex drawParams,
- DMSetDrawOptionsMappedTex drawParamsMapped,
- DMCompareDrawOptions compareDrawOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- struct BMLoop *(*looptris)[3] = em->looptris;
- BMFace *efa;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- MLoopUV *luv[3], dummyluv = {{0}};
- MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
- unsigned char(*color_vert_array)[4] = em->derivedVertColor;
- bool has_uv = (cd_loop_uv_offset != -1);
- bool has_vcol_preview = (color_vert_array != NULL);
- bool has_vcol = (cd_loop_color_offset != -1) && (has_vcol_preview == false);
- bool has_vcol_any = (has_vcol_preview || has_vcol);
- int i;
-
- (void) compareDrawOptions;
-
- luv[0] = luv[1] = luv[2] = &dummyluv;
-
- // dummylcol.r = dummylcol.g = dummylcol.b = dummylcol.a = 255; /* UNUSED */
-
- /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
- BM_mesh_elem_index_ensure(bm, BM_FACE);
-
- /* call again below is ok */
- if (has_vcol_preview) {
- BM_mesh_elem_index_ensure(bm, BM_VERT);
- }
-
- if (bmdm->vertexCos) {
- /* add direct access */
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
-
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT);
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL;
- /*unsigned char *cp = NULL;*/ /*UNUSED*/
- int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH);
- DMDrawOption draw_option;
-
- efa = ltri[0]->f;
-
- if (drawParams) {
- draw_option = drawParams(tp, has_vcol, efa->mat_nr);
- }
- else if (drawParamsMapped)
- draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr);
- else
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
-
- if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset);
- if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset);
- else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
-
- glBegin(GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
-
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- else {
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[0]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[0]->v)]);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[1]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[1]->v)]);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(vertexNos[BM_elem_index_get(ltri[2]->v)]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[2]->v)]);
- }
- glEnd();
- }
- }
- }
- else {
- BM_mesh_elem_index_ensure(bm, lnors ? BM_LOOP | BM_VERT : BM_VERT);
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- MTexPoly *tp = (cd_poly_tex_offset != -1) ? BM_ELEM_CD_GET_VOID_P(ltri[0]->f, cd_poly_tex_offset) : NULL;
- /*unsigned char *cp = NULL;*/ /*UNUSED*/
- int drawSmooth = lnors || BM_elem_flag_test(ltri[0]->f, BM_ELEM_SMOOTH);
- DMDrawOption draw_option;
-
- efa = ltri[0]->f;
-
- if (drawParams)
- draw_option = drawParams(tp, has_vcol, efa->mat_nr);
- else if (drawParamsMapped)
- draw_option = drawParamsMapped(userData, BM_elem_index_get(efa), efa->mat_nr);
- else
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
-
- if (has_uv) bmdm_get_tri_uv(ltri, luv, cd_loop_uv_offset);
- if (has_vcol) bmdm_get_tri_col(ltri, lcol, cd_loop_color_offset);
- else if (has_vcol_preview) bmdm_get_tri_colpreview(ltri, lcol, color_vert_array);
-
- glBegin(GL_TRIANGLES);
- if (!drawSmooth) {
- glNormal3fv(efa->no);
-
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- glVertex3fv(ltri[0]->v->co);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- glVertex3fv(ltri[1]->v->co);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- glVertex3fv(ltri[2]->v->co);
- }
- else {
- glTexCoord2fv(luv[0]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[0]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[0])]);
- else glNormal3fv(ltri[0]->v->no);
- glVertex3fv(ltri[0]->v->co);
-
- glTexCoord2fv(luv[1]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[1]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[1])]);
- else glNormal3fv(ltri[1]->v->no);
- glVertex3fv(ltri[1]->v->co);
-
- glTexCoord2fv(luv[2]->uv);
- if (has_vcol_any) glColor4ubv((const GLubyte *)&(lcol[2]->r));
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[2])]);
- else glNormal3fv(ltri[2]->v->no);
- glVertex3fv(ltri[2]->v->co);
- }
- glEnd();
- }
- }
- }
-}
-
-static void emDM_drawFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag UNUSED(flag))
-{
- emDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
-}
-
-static void emDM_drawMappedFacesTex(
- DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag UNUSED(flag))
-{
- emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
-}
-
-/**
- * \note
- *
- * For UV's:
- * const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, attribs->tface[i].em_offset);
- *
- * This is intentionally different to calling:
- * CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPUV, i);
- *
- * ... because the material may use layer names to select different UV's
- * see: [#34378]
- */
-static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const BMLoop *loop)
-{
- BMVert *eve = loop->v;
- int i;
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
-
- if (attribs->totorco) {
- int index = BM_elem_index_get(eve);
- const float *orco = (attribs->orco.array) ? attribs->orco.array[index] : zero;
-
- if (attribs->orco.gl_texco)
- glTexCoord3fv(orco);
- else
- glVertexAttrib3fv(attribs->orco.gl_index, orco);
- }
- for (i = 0; i < attribs->tottface; i++) {
- const float *uv;
-
- if (attribs->tface[i].em_offset != -1) {
- const MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(loop, attribs->tface[i].em_offset);
- uv = luv->uv;
- }
- else {
- uv = zero;
- }
-
- if (attribs->tface[i].gl_texco)
- glTexCoord2fv(uv);
- else
- glVertexAttrib2fv(attribs->tface[i].gl_index, uv);
- }
- for (i = 0; i < attribs->totmcol; i++) {
- float col[4];
- if (attribs->mcol[i].em_offset != -1) {
- const MLoopCol *cp = BM_ELEM_CD_GET_VOID_P(loop, attribs->mcol[i].em_offset);
- rgba_uchar_to_float(col, &cp->r);
- }
- else {
- col[0] = 0.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 0.0f;
- }
- glVertexAttrib4fv(attribs->mcol[i].gl_index, col);
- }
-
- for (i = 0; i < attribs->tottang; i++) {
- const float *tang;
- if (attribs->tang[i].em_offset != -1) {
- tang = attribs->tang[i].array[BM_elem_index_get(loop)];
- }
- else {
- tang = zero;
- }
- glVertexAttrib4fv(attribs->tang[i].gl_index, tang);
- }
-}
-
-static void emDM_drawMappedFacesGLSL(
- DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- struct BMLoop *(*looptris)[3] = em->looptris;
- /* add direct access */
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-
- BMFace *efa;
- DMVertexAttribs attribs;
- GPUVertexAttribs gattribs;
-
- int i, matnr, new_matnr, fi;
- bool do_draw;
-
- do_draw = false;
- matnr = -1;
-
- memset(&attribs, 0, sizeof(attribs));
-
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
-
- if (setDrawOptions && (setDrawOptions(userData, BM_elem_index_get(efa)) == DM_DRAW_OPTION_SKIP))
- continue;
-
- /* material */
- new_matnr = efa->mat_nr + 1;
- if (new_matnr != matnr) {
- if (matnr != -1)
- glEnd();
-
- do_draw = setMaterial(matnr = new_matnr, &gattribs);
- if (do_draw) {
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- DM_draw_attrib_vertex_uniforms(&attribs);
- if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
- BM_mesh_elem_index_ensure(bm, BM_LOOP);
- }
- }
-
- glBegin(GL_TRIANGLES);
- }
-
- if (do_draw) {
-
- /* draw face */
- drawSmooth = lnors || BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
-
- if (!drawSmooth) {
- if (vertexCos) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
- }
- }
- else {
- glNormal3fv(efa->no);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- else {
- if (vertexCos) {
- for (fi = 0; fi < 3; fi++) {
- const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(vertexNos[j]);
- glVertex3fv(vertexCos[j]);
- }
- }
- else {
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(ltri[fi]->v->no);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- }
- }
-
- if (matnr != -1) {
- glEnd();
- }
-}
-
-static void emDM_drawFacesGLSL(
- DerivedMesh *dm,
- int (*setMaterial)(int matnr, void *attribs))
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-static void emDM_drawMappedFacesMat(
- DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMEditMesh *em = bmdm->em;
- BMesh *bm = em->bm;
- struct BMLoop *(*looptris)[3] = em->looptris;
- const float (*vertexCos)[3] = bmdm->vertexCos;
- const float (*vertexNos)[3];
- const float (*polyNos)[3];
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- BMFace *efa;
- DMVertexAttribs attribs = {{{NULL}}};
- GPUVertexAttribs gattribs;
- int i, matnr, new_matnr, fi;
-
- matnr = -1;
-
- emDM_ensureVertNormals(bmdm);
- emDM_ensurePolyNormals(bmdm);
-
- vertexNos = bmdm->vertexNos;
- polyNos = bmdm->polyNos;
-
- BM_mesh_elem_index_ensure(bm, (BM_VERT | BM_FACE) | (lnors ? BM_LOOP : 0));
-
- for (i = 0; i < em->tottri; i++) {
- BMLoop **ltri = looptris[i];
- int drawSmooth;
-
- efa = ltri[0]->f;
-
- /* face hiding */
- if (setFace && !setFace(userData, BM_elem_index_get(efa)))
- continue;
-
- /* material */
- new_matnr = efa->mat_nr + 1;
- if (new_matnr != matnr) {
- if (matnr != -1)
- glEnd();
-
- setMaterial(userData, matnr = new_matnr, &gattribs);
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
- BM_mesh_elem_index_ensure(bm, BM_LOOP);
- }
-
- glBegin(GL_TRIANGLES);
- }
-
- /* draw face */
- drawSmooth = lnors || BM_elem_flag_test(efa, BM_ELEM_SMOOTH);
-
- if (!drawSmooth) {
- if (vertexCos) {
- glNormal3fv(polyNos[BM_elem_index_get(efa)]);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- glVertex3fv(vertexCos[BM_elem_index_get(ltri[fi]->v)]);
- }
- }
- else {
- glNormal3fv(efa->no);
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- else {
- if (vertexCos) {
- for (fi = 0; fi < 3; fi++) {
- const int j = BM_elem_index_get(ltri[fi]->v);
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(vertexNos[j]);
- glVertex3fv(vertexCos[j]);
- }
- }
- else {
- for (fi = 0; fi < 3; fi++) {
- emdm_pass_attrib_vertex_glsl(&attribs, ltri[fi]);
- if (lnors) glNormal3fv(lnors[BM_elem_index_get(ltri[fi])]);
- else glNormal3fv(ltri[fi]->v->no);
- glVertex3fv(ltri[fi]->v->co);
- }
- }
- }
- }
-
- if (matnr != -1) {
- glEnd();
- }
-}
-
-static void emDM_getMinMax(DerivedMesh *dm, float r_min[3], float r_max[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *eve;
- BMIter iter;
- int i;
-
- if (bm->totvert) {
- if (bmdm->vertexCos) {
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- minmax_v3v3_v3(r_min, r_max, bmdm->vertexCos[i]);
- }
- }
- else {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- minmax_v3v3_v3(r_min, r_max, eve->co);
- }
- }
- }
- else {
- zero_v3(r_min);
- zero_v3(r_max);
- }
-}
-static int emDM_getNumVerts(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->bm->totvert;
-}
-
-static int emDM_getNumEdges(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->bm->totedge;
-}
-
-static int emDM_getNumTessFaces(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->tottri;
-}
-
-static int emDM_getNumLoops(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->bm->totloop;
-}
-
-static int emDM_getNumPolys(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return bmdm->em->bm->totface;
-}
-
-static void bmvert_to_mvert(BMesh *bm, BMVert *ev, MVert *r_vert)
-{
- const float *f;
-
- copy_v3_v3(r_vert->co, ev->co);
-
- normal_float_to_short_v3(r_vert->no, ev->no);
-
- r_vert->flag = BM_vert_flag_to_mflag(ev);
-
- if ((f = CustomData_bmesh_get(&bm->vdata, ev->head.data, CD_BWEIGHT))) {
- r_vert->bweight = (unsigned char)((*f) * 255.0f);
- }
-}
-
-static void emDM_getVert(DerivedMesh *dm, int index, MVert *r_vert)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *ev;
-
- if (UNLIKELY(index < 0 || index >= bm->totvert)) {
- BLI_assert(!"error in emDM_getVert");
- return;
- }
-
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- ev = bm->vtable[index]; /* should be BM_vert_at_index() */
- // ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */
-
- bmvert_to_mvert(bm, ev, r_vert);
- if (bmdm->vertexCos)
- copy_v3_v3(r_vert->co, bmdm->vertexCos[index]);
-}
-
-static void emDM_getVertCo(DerivedMesh *dm, int index, float r_co[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
-
- if (UNLIKELY(index < 0 || index >= bm->totvert)) {
- BLI_assert(!"error in emDM_getVertCo");
- return;
- }
-
- if (bmdm->vertexCos) {
- copy_v3_v3(r_co, bmdm->vertexCos[index]);
- }
- else {
- BMVert *ev;
-
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- ev = bm->vtable[index]; /* should be BM_vert_at_index() */
- // ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */
- copy_v3_v3(r_co, ev->co);
- }
-}
-
-static void emDM_getVertNo(DerivedMesh *dm, int index, float r_no[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
-
- if (UNLIKELY(index < 0 || index >= bm->totvert)) {
- BLI_assert(!"error in emDM_getVertNo");
- return;
- }
-
-
- if (bmdm->vertexCos) {
- emDM_ensureVertNormals(bmdm);
- copy_v3_v3(r_no, bmdm->vertexNos[index]);
- }
- else {
- BMVert *ev;
-
- BLI_assert((bm->elem_table_dirty & BM_VERT) == 0);
- ev = bm->vtable[index]; /* should be BM_vert_at_index() */
- // ev = BM_vert_at_index(bm, index); /* warning, does list loop, _not_ ideal */
- copy_v3_v3(r_no, ev->no);
- }
-}
-
-static void emDM_getPolyNo(DerivedMesh *dm, int index, float r_no[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
-
- if (UNLIKELY(index < 0 || index >= bm->totface)) {
- BLI_assert(!"error in emDM_getPolyNo");
- return;
- }
-
- if (bmdm->vertexCos) {
- emDM_ensurePolyNormals(bmdm);
- copy_v3_v3(r_no, bmdm->polyNos[index]);
- }
- else {
- BMFace *efa;
-
- BLI_assert((bm->elem_table_dirty & BM_FACE) == 0);
- efa = bm->ftable[index]; /* should be BM_vert_at_index() */
- // efa = BM_face_at_index(bm, index); /* warning, does list loop, _not_ ideal */
- copy_v3_v3(r_no, efa->no);
- }
-}
-
-static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *r_edge)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMEdge *e;
- const float *f;
-
- if (UNLIKELY(index < 0 || index >= bm->totedge)) {
- BLI_assert(!"error in emDM_getEdge");
- return;
- }
-
- BLI_assert((bm->elem_table_dirty & BM_EDGE) == 0);
- e = bm->etable[index]; /* should be BM_edge_at_index() */
- // e = BM_edge_at_index(bm, index); /* warning, does list loop, _not_ ideal */
-
- r_edge->flag = BM_edge_flag_to_mflag(e);
-
- r_edge->v1 = BM_elem_index_get(e->v1);
- r_edge->v2 = BM_elem_index_get(e->v2);
-
- if ((f = CustomData_bmesh_get(&bm->edata, e->head.data, CD_BWEIGHT))) {
- r_edge->bweight = (unsigned char)((*f) * 255.0f);
- }
- if ((f = CustomData_bmesh_get(&bm->edata, e->head.data, CD_CREASE))) {
- r_edge->crease = (unsigned char)((*f) * 255.0f);
- }
-}
-
-static void emDM_getTessFace(DerivedMesh *dm, int index, MFace *r_face)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMFace *ef;
- BMLoop **ltri;
-
- if (UNLIKELY(index < 0 || index >= bmdm->em->tottri)) {
- BLI_assert(!"error in emDM_getTessFace");
- return;
- }
-
- ltri = bmdm->em->looptris[index];
-
- ef = ltri[0]->f;
-
- r_face->mat_nr = (unsigned char) ef->mat_nr;
- r_face->flag = BM_face_flag_to_mflag(ef);
-
- r_face->v1 = BM_elem_index_get(ltri[0]->v);
- r_face->v2 = BM_elem_index_get(ltri[1]->v);
- r_face->v3 = BM_elem_index_get(ltri[2]->v);
- r_face->v4 = 0;
-
- test_index_face(r_face, NULL, 0, 3);
-}
-
-static void emDM_copyVertArray(DerivedMesh *dm, MVert *r_vert)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *eve;
- BMIter iter;
- const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
-
- if (bmdm->vertexCos) {
- int i;
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(r_vert->co, bmdm->vertexCos[i]);
- normal_float_to_short_v3(r_vert->no, eve->no);
- r_vert->flag = BM_vert_flag_to_mflag(eve);
-
- r_vert->bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset) : 0;
-
- r_vert++;
- }
- }
- else {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- copy_v3_v3(r_vert->co, eve->co);
- normal_float_to_short_v3(r_vert->no, eve->no);
- r_vert->flag = BM_vert_flag_to_mflag(eve);
-
- r_vert->bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eve, cd_vert_bweight_offset) : 0;
-
- r_vert++;
- }
- }
-}
-
-static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *r_edge)
-{
- BMesh *bm = ((EditDerivedBMesh *)dm)->em->bm;
- BMEdge *eed;
- BMIter iter;
-
- const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
- const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- r_edge->v1 = BM_elem_index_get(eed->v1);
- r_edge->v2 = BM_elem_index_get(eed->v2);
-
- r_edge->flag = BM_edge_flag_to_mflag(eed);
-
- r_edge->crease = (cd_edge_crease_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_crease_offset) : 0;
- r_edge->bweight = (cd_edge_bweight_offset != -1) ? BM_ELEM_CD_GET_FLOAT_AS_UCHAR(eed, cd_edge_bweight_offset) : 0;
-
- r_edge++;
- }
-}
-
-static void emDM_copyTessFaceArray(DerivedMesh *dm, MFace *r_face)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- struct BMLoop *(*looptris)[3] = bmdm->em->looptris;
- BMFace *ef;
- int i;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT);
-
- for (i = 0; i < bmdm->em->tottri; i++, r_face++) {
- BMLoop **ltri = looptris[i];
- ef = ltri[0]->f;
-
- r_face->mat_nr = (unsigned char) ef->mat_nr;
-
- r_face->flag = BM_face_flag_to_mflag(ef);
- r_face->edcode = 0;
-
- r_face->v1 = BM_elem_index_get(ltri[0]->v);
- r_face->v2 = BM_elem_index_get(ltri[1]->v);
- r_face->v3 = BM_elem_index_get(ltri[2]->v);
- r_face->v4 = 0;
-
- test_index_face(r_face, NULL, 0, 3);
- }
-}
-
-static void emDM_copyLoopArray(DerivedMesh *dm, MLoop *r_loop)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMIter iter;
- BMFace *efa;
-
- BM_mesh_elem_index_ensure(bm, BM_VERT | BM_EDGE);
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- r_loop->v = BM_elem_index_get(l_iter->v);
- r_loop->e = BM_elem_index_get(l_iter->e);
- r_loop++;
- } while ((l_iter = l_iter->next) != l_first);
- }
-}
-
-static void emDM_copyPolyArray(DerivedMesh *dm, MPoly *r_poly)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMIter iter;
- BMFace *efa;
- int i;
-
- i = 0;
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- r_poly->flag = BM_face_flag_to_mflag(efa);
- r_poly->loopstart = i;
- r_poly->totloop = efa->len;
- r_poly->mat_nr = efa->mat_nr;
-
- r_poly++;
- i += efa->len;
- }
-}
-
-static void *emDM_getTessFaceDataArray(DerivedMesh *dm, int type)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- void *datalayer;
-
- datalayer = DM_get_tessface_data_layer(dm, type);
- if (datalayer)
- return datalayer;
-
- /* layers are store per face for editmesh, we convert to a temporary
- * data layer array in the derivedmesh when these are requested */
- if (type == CD_MTFACE || type == CD_MCOL) {
- const char *bmdata;
- char *data;
- bool has_type_source = false;
-
- if (type == CD_MTFACE) {
- has_type_source = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY);
- }
- else {
- has_type_source = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL);
- }
-
- if (has_type_source) {
- /* offset = bm->pdata.layers[index].offset; */ /* UNUSED */
- BMLoop *(*looptris)[3] = bmdm->em->looptris;
- const int size = CustomData_sizeof(type);
- int i, j;
-
- DM_add_tessface_layer(dm, type, CD_CALLOC, NULL);
- const int index = CustomData_get_layer_index(&dm->faceData, type);
- dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
-
- data = datalayer = DM_get_tessface_data_layer(dm, type);
-
- if (type == CD_MTFACE) {
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
- const int cd_poly_tex_offset = CustomData_get_offset(&bm->pdata, CD_MTEXPOLY);
-
- for (i = 0; i < bmdm->em->tottri; i++, data += size) {
- BMFace *efa = looptris[i][0]->f;
-
- // bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY);
- bmdata = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
-
- ME_MTEXFACE_CPY(((MTFace *)data), ((const MTexPoly *)bmdata));
- for (j = 0; j < 3; j++) {
- // bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPUV);
- bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_uv_offset);
- copy_v2_v2(((MTFace *)data)->uv[j], ((const MLoopUV *)bmdata)->uv);
- }
- }
- }
- else {
- const int cd_loop_color_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
- for (i = 0; i < bmdm->em->tottri; i++, data += size) {
- for (j = 0; j < 3; j++) {
- // bmdata = CustomData_bmesh_get(&bm->ldata, looptris[i][j]->head.data, CD_MLOOPCOL);
- bmdata = BM_ELEM_CD_GET_VOID_P(looptris[i][j], cd_loop_color_offset);
- MESH_MLOOPCOL_TO_MCOL(((const MLoopCol *)bmdata), (((MCol *)data) + j));
- }
- }
- }
- }
- }
-
- /* Special handling for CD_TESSLOOPNORMAL, we generate it on demand as well. */
- if (type == CD_TESSLOOPNORMAL) {
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-
- if (lnors) {
- BMLoop *(*looptris)[3] = bmdm->em->looptris;
- short (*tlnors)[4][3], (*tlnor)[4][3];
- int index, i, j;
-
- DM_add_tessface_layer(dm, type, CD_CALLOC, NULL);
- index = CustomData_get_layer_index(&dm->faceData, type);
- dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
-
- tlnor = tlnors = DM_get_tessface_data_layer(dm, type);
-
- BM_mesh_elem_index_ensure(bm, BM_LOOP);
-
- for (i = 0; i < bmdm->em->tottri; i++, tlnor++, looptris++) {
- for (j = 0; j < 3; j++) {
- normal_float_to_short_v3((*tlnor)[j], lnors[BM_elem_index_get((*looptris)[j])]);
- }
- }
- }
- }
-
- return datalayer;
-}
-
-static void emDM_getVertCos(DerivedMesh *dm, float (*r_cos)[3])
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BMesh *bm = bmdm->em->bm;
- BMVert *eve;
- BMIter iter;
- int i;
-
- if (bmdm->vertexCos) {
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(r_cos[i], bmdm->vertexCos[i]);
- }
- }
- else {
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- copy_v3_v3(r_cos[i], eve->co);
- }
- }
-}
-
-static void emDM_release(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- if (DM_release(dm)) {
- if (bmdm->vertexCos) {
- MEM_freeN((void *)bmdm->vertexCos);
- if (bmdm->vertexNos) {
- MEM_freeN((void *)bmdm->vertexNos);
- }
- if (bmdm->polyNos) {
- MEM_freeN((void *)bmdm->polyNos);
- }
- }
-
- if (bmdm->polyCos) {
- MEM_freeN((void *)bmdm->polyCos);
- }
-
- MEM_freeN(bmdm);
- }
-}
-
-static CustomData *bmDm_getVertDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->em->bm->vdata;
-}
-
-static CustomData *bmDm_getEdgeDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->em->bm->edata;
-}
-
-static CustomData *bmDm_getTessFaceDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->dm.faceData;
-}
-
-static CustomData *bmDm_getLoopDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->em->bm->ldata;
-}
-
-static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm)
-{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
-
- return &bmdm->em->bm->pdata;
-}
-
-/**
- * \note This may be called per-draw,
- * avoid allocating large arrays where possible and keep this a thin wrapper for #BMesh.
- */
-DerivedMesh *getEditDerivedBMesh(
- BMEditMesh *em, struct Object *UNUSED(ob),
- CustomDataMask data_mask,
- float (*vertexCos)[3])
-{
- EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__);
- BMesh *bm = em->bm;
-
- bmdm->em = em;
-
- DM_init((DerivedMesh *)bmdm, DM_TYPE_EDITBMESH, bm->totvert,
- bm->totedge, em->tottri, bm->totloop, bm->totface);
-
- /* could also get from the objects mesh directly */
- bmdm->dm.cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
-
- bmdm->dm.getVertCos = emDM_getVertCos;
- bmdm->dm.getMinMax = emDM_getMinMax;
-
- bmdm->dm.getVertDataLayout = bmDm_getVertDataLayout;
- bmdm->dm.getEdgeDataLayout = bmDm_getEdgeDataLayout;
- bmdm->dm.getTessFaceDataLayout = bmDm_getTessFaceDataLayout;
- bmdm->dm.getLoopDataLayout = bmDm_getLoopDataLayout;
- bmdm->dm.getPolyDataLayout = bmDm_getPolyDataLayout;
-
- bmdm->dm.getNumVerts = emDM_getNumVerts;
- bmdm->dm.getNumEdges = emDM_getNumEdges;
- bmdm->dm.getNumTessFaces = emDM_getNumTessFaces;
- bmdm->dm.getNumLoops = emDM_getNumLoops;
- bmdm->dm.getNumPolys = emDM_getNumPolys;
-
- bmdm->dm.getVert = emDM_getVert;
- bmdm->dm.getVertCo = emDM_getVertCo;
- bmdm->dm.getVertNo = emDM_getVertNo;
- bmdm->dm.getPolyNo = emDM_getPolyNo;
- bmdm->dm.getEdge = emDM_getEdge;
- bmdm->dm.getTessFace = emDM_getTessFace;
- bmdm->dm.copyVertArray = emDM_copyVertArray;
- bmdm->dm.copyEdgeArray = emDM_copyEdgeArray;
- bmdm->dm.copyTessFaceArray = emDM_copyTessFaceArray;
- bmdm->dm.copyLoopArray = emDM_copyLoopArray;
- bmdm->dm.copyPolyArray = emDM_copyPolyArray;
-
- bmdm->dm.getTessFaceDataArray = emDM_getTessFaceDataArray;
-
- bmdm->dm.calcNormals = emDM_calcNormals;
- bmdm->dm.calcLoopNormals = emDM_calcLoopNormals;
- bmdm->dm.calcLoopNormalsSpaceArray = emDM_calcLoopNormalsSpaceArray;
- bmdm->dm.calcLoopTangents = emDM_calc_loop_tangents;
- bmdm->dm.recalcTessellation = emDM_recalcTessellation;
- bmdm->dm.recalcLoopTri = emDM_recalcLoopTri;
-
- bmdm->dm.foreachMappedVert = emDM_foreachMappedVert;
- bmdm->dm.foreachMappedLoop = emDM_foreachMappedLoop;
- bmdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
- bmdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter;
-
- bmdm->dm.drawEdges = emDM_drawEdges;
- bmdm->dm.drawMappedEdges = emDM_drawMappedEdges;
- bmdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp;
- bmdm->dm.drawMappedFaces = emDM_drawMappedFaces;
- bmdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex;
- bmdm->dm.drawMappedFacesGLSL = emDM_drawMappedFacesGLSL;
- bmdm->dm.drawMappedFacesMat = emDM_drawMappedFacesMat;
- bmdm->dm.drawFacesTex = emDM_drawFacesTex;
- bmdm->dm.drawFacesGLSL = emDM_drawFacesGLSL;
- bmdm->dm.drawUVEdges = emDM_drawUVEdges;
-
- bmdm->dm.release = emDM_release;
-
- bmdm->vertexCos = (const float (*)[3])vertexCos;
- bmdm->dm.deformedOnly = (vertexCos != NULL);
-
- const int cd_dvert_offset = (data_mask & CD_MASK_MDEFORMVERT) ?
- CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT) : -1;
-
- if (cd_dvert_offset != -1) {
- BMIter iter;
- BMVert *eve;
- int i;
-
- DM_add_vert_layer(&bmdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT,
- BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
- }
- }
-
- const int cd_skin_offset = (data_mask & CD_MASK_MVERT_SKIN) ?
- CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN) : -1;
-
- if (cd_skin_offset != -1) {
- BMIter iter;
- BMVert *eve;
- int i;
-
- DM_add_vert_layer(&bmdm->dm, CD_MVERT_SKIN, CD_CALLOC, NULL);
-
- BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
- DM_set_vert_data(&bmdm->dm, i, CD_MVERT_SKIN,
- BM_ELEM_CD_GET_VOID_P(eve, cd_skin_offset));
- }
- }
-
- return (DerivedMesh *)bmdm;
-}
-
-
-
/* -------------------------------------------------------------------- */
/* StatVis Functions */
@@ -2375,7 +105,7 @@ static void statvis_calc_overhang(
/* fallback max */
{
float fcol[3];
- weight_to_rgb(fcol, 1.0f);
+ BKE_defvert_weight_to_rgb(fcol, 1.0f);
rgb_float_to_uchar(col_fallback_max, fcol);
}
@@ -2389,7 +119,7 @@ static void statvis_calc_overhang(
fac = (fac - min) * minmax_irange;
fac = 1.0f - fac;
CLAMP(fac, 0.0f, 1.0f);
- weight_to_rgb(fcol, fac);
+ BKE_defvert_weight_to_rgb(fcol, fac);
rgb_float_to_uchar(r_face_colors[index], fcol);
}
else {
@@ -2524,7 +254,7 @@ static void statvis_calc_thickness(
fac = (fac - min) * minmax_irange;
fac = 1.0f - fac;
CLAMP(fac, 0.0f, 1.0f);
- weight_to_rgb(fcol, fac);
+ BKE_defvert_weight_to_rgb(fcol, fac);
rgb_float_to_uchar(r_face_colors[i], fcol);
}
else {
@@ -2563,7 +293,7 @@ static void statvis_calc_intersect(
overlap = BKE_bmbvh_overlap(bmtree, bmtree, &overlap_len);
/* same for all faces */
- weight_to_rgb(fcol, 1.0f);
+ BKE_defvert_weight_to_rgb(fcol, 1.0f);
rgb_float_to_uchar(col, fcol);
if (overlap) {
@@ -2650,7 +380,7 @@ static void statvis_calc_distort(
float fcol[3];
fac = (fac - min) * minmax_irange;
CLAMP(fac, 0.0f, 1.0f);
- weight_to_rgb(fcol, fac);
+ BKE_defvert_weight_to_rgb(fcol, fac);
rgb_float_to_uchar(r_face_colors[index], fcol);
}
else {
@@ -2700,7 +430,7 @@ static void statvis_calc_sharp(
float fcol[3];
fac = (fac - min) * minmax_irange;
CLAMP(fac, 0.0f, 1.0f);
- weight_to_rgb(fcol, fac);
+ BKE_defvert_weight_to_rgb(fcol, fac);
rgb_float_to_uchar(r_vert_colors[i], fcol);
}
else {
@@ -2710,18 +440,15 @@ static void statvis_calc_sharp(
}
void BKE_editmesh_statvis_calc(
- BMEditMesh *em, DerivedMesh *dm,
+ BMEditMesh *em, EditMeshData *emd,
const MeshStatVis *statvis)
{
- EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
- BLI_assert(dm == NULL || dm->type == DM_TYPE_EDITBMESH);
-
switch (statvis->type) {
case SCE_STATVIS_OVERHANG:
{
BKE_editmesh_color_ensure(em, BM_FACE);
statvis_calc_overhang(
- em, bmdm ? bmdm->polyNos : NULL,
+ em, emd ? emd->polyNos : NULL,
statvis->overhang_min / (float)M_PI,
statvis->overhang_max / (float)M_PI,
statvis->overhang_axis,
@@ -2733,7 +460,7 @@ void BKE_editmesh_statvis_calc(
const float scale = 1.0f / mat4_to_scale(em->ob->obmat);
BKE_editmesh_color_ensure(em, BM_FACE);
statvis_calc_thickness(
- em, bmdm ? bmdm->vertexCos : NULL,
+ em, emd ? emd->vertexCos : NULL,
statvis->thickness_min * scale,
statvis->thickness_max * scale,
statvis->thickness_samples,
@@ -2744,7 +471,7 @@ void BKE_editmesh_statvis_calc(
{
BKE_editmesh_color_ensure(em, BM_FACE);
statvis_calc_intersect(
- em, bmdm ? bmdm->vertexCos : NULL,
+ em, emd ? emd->vertexCos : NULL,
em->derivedFaceColor);
break;
}
@@ -2752,11 +479,12 @@ void BKE_editmesh_statvis_calc(
{
BKE_editmesh_color_ensure(em, BM_FACE);
- if (bmdm)
- emDM_ensurePolyNormals(bmdm);
+ if (emd) {
+ BKE_editmesh_cache_ensure_poly_normals(em, emd);
+ }
statvis_calc_distort(
- em, bmdm ? bmdm->vertexCos : NULL, bmdm ? bmdm->polyNos : NULL,
+ em, emd ? emd->vertexCos : NULL, emd ? emd->polyNos : NULL,
statvis->distort_min,
statvis->distort_max,
em->derivedFaceColor);
@@ -2766,7 +494,7 @@ void BKE_editmesh_statvis_calc(
{
BKE_editmesh_color_ensure(em, BM_VERT);
statvis_calc_sharp(
- em, bmdm ? bmdm->vertexCos : NULL,
+ em, emd ? emd->vertexCos : NULL,
statvis->sharp_min,
statvis->sharp_max,
/* in this case they are vertex colors */
@@ -2799,14 +527,14 @@ static void cage_mapped_verts_callback(
}
}
-float (*BKE_editmesh_vertexCos_get(BMEditMesh *em, Scene *scene, int *r_numVerts))[3]
+float (*BKE_editmesh_vertexCos_get(struct Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, int *r_numVerts))[3]
{
- DerivedMesh *cage, *final;
+ Mesh *cage, *final;
BLI_bitmap *visit_bitmap;
struct CageUserData data;
float (*cos_cage)[3];
- cage = editbmesh_get_derived_cage_and_final(scene, em->ob, em, CD_MASK_BAREMESH, &final);
+ cage = editbmesh_get_eval_cage_and_final(depsgraph, scene, em->ob, em, CD_MASK_BAREMESH, &final);
cos_cage = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage");
/* when initializing cage verts, we only want the first cage coordinate for each vertex,
@@ -2817,7 +545,7 @@ float (*BKE_editmesh_vertexCos_get(BMEditMesh *em, Scene *scene, int *r_numVerts
data.cos_cage = cos_cage;
data.visit_bitmap = visit_bitmap;
- cage->foreachMappedVert(cage, cage_mapped_verts_callback, &data, DM_FOREACH_NOP);
+ BKE_mesh_foreach_mapped_vert(cage, cage_mapped_verts_callback, &data, MESH_FOREACH_NOP);
MEM_freeN(visit_bitmap);
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index fea3c24d322..11f3594da04 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -39,6 +39,7 @@
#include "BKE_editmesh.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library.h"
BMEditMesh *BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
@@ -58,7 +59,7 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em)
BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__);
*em_copy = *em;
- em_copy->derivedCage = em_copy->derivedFinal = NULL;
+ em_copy->mesh_eval_cage = em_copy->mesh_eval_final = NULL;
em_copy->derivedVertColor = NULL;
em_copy->derivedVertColorLen = 0;
@@ -89,11 +90,13 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob)
{
BLI_assert(ob->type == OB_MESH);
/* sanity check */
+#if 0 /* disable in mutlti-object edit. */
#ifndef NDEBUG
if (((Mesh *)ob->data)->edit_btmesh) {
BLI_assert(((Mesh *)ob->data)->edit_btmesh->ob == ob);
}
#endif
+#endif
return ((Mesh *)ob->data)->edit_btmesh;
}
@@ -112,18 +115,6 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
BMLoop *(*looptris)[3];
-#if 0
- /* note, we could be clever and re-use this array but would need to ensure
- * its realloced at some point, for now just free it */
- if (em->looptris) MEM_freeN(em->looptris);
-
- /* Use em->tottri when set, this means no reallocs while transforming,
- * (unless scanfill fails), otherwise... */
- /* allocate the length of totfaces, avoid many small reallocs,
- * if all faces are tri's it will be correct, quads == 2x allocs */
- BLI_array_reserve(looptris, (em->tottri && em->tottri < bm->totface * 3) ? em->tottri : bm->totface);
-#else
-
/* this means no reallocs for quad dominant models, for */
if ((em->looptris != NULL) &&
/* (*em->tottri >= looptris_tot)) */
@@ -137,8 +128,6 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em)
looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__);
}
-#endif
-
em->looptris = looptris;
/* after allocating the em->looptris, we're ready to tessellate */
@@ -152,51 +141,25 @@ void BKE_editmesh_tessface_calc(BMEditMesh *em)
/* commented because editbmesh_build_data() ensures we get tessfaces */
#if 0
- if (em->derivedFinal && em->derivedFinal == em->derivedCage) {
- if (em->derivedFinal->recalcTessellation)
- em->derivedFinal->recalcTessellation(em->derivedFinal);
+ if (em->mesh_eval_final && em->mesh_eval_final == em->mesh_eval_cage) {
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
}
- else if (em->derivedFinal) {
- if (em->derivedCage->recalcTessellation)
- em->derivedCage->recalcTessellation(em->derivedCage);
- if (em->derivedFinal->recalcTessellation)
- em->derivedFinal->recalcTessellation(em->derivedFinal);
+ else if (em->mesh_eval_final) {
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_final);
+ BKE_mesh_runtime_looptri_ensure(em->mesh_eval_cage);
}
#endif
}
-void BKE_editmesh_update_linked_customdata(BMEditMesh *em)
-{
- BMesh *bm = em->bm;
- int act;
-
- if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) {
- act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY);
- CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act);
- }
-}
-
void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
{
- if (em->derivedCage) {
- em->derivedCage->needsFree = 1;
- em->derivedCage->release(em->derivedCage);
+ if (em->mesh_eval_cage) {
+ BKE_id_free(NULL, em->mesh_eval_cage);
}
- if (em->derivedFinal && em->derivedFinal != em->derivedCage) {
- em->derivedFinal->needsFree = 1;
- em->derivedFinal->release(em->derivedFinal);
+ if (em->mesh_eval_final && em->mesh_eval_final != em->mesh_eval_cage) {
+ BKE_id_free(NULL, em->mesh_eval_final);
}
-
- em->derivedCage = em->derivedFinal = NULL;
+ em->mesh_eval_cage = em->mesh_eval_final = NULL;
}
/*does not free the BMEditMesh struct itself*/
@@ -264,3 +227,24 @@ float (*BKE_editmesh_vertexCos_get_orco(BMEditMesh *em, int *r_numVerts))[3]
return orco;
}
+
+void BKE_editmesh_lnorspace_update(BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+
+ /* We need to create clnors data if none exist yet, otherwise there is no way to edit them.
+ * Similar code to MESH_OT_customdata_custom_splitnormals_add operator, we want to keep same shading
+ * in case we were using autosmooth so far...
+ * Note: there is a problem here, which is that if someone starts a normal editing operation on previously
+ * autosmooth-ed mesh, and cancel that operation, generated clnors data remain, with related sharp edges
+ * (and hence autosmooth is 'lost').
+ * Not sure how critical this is, and how to fix that issue? */
+ if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ Mesh *me = em->ob->data;
+ if (me->flag & ME_AUTOSMOOTH) {
+ BM_edges_sharp_from_angle_set(bm, me->smoothresh);
+ }
+ }
+
+ BM_lnorspace_update(bm);
+}
diff --git a/source/blender/blenkernel/intern/editmesh_cache.c b/source/blender/blenkernel/intern/editmesh_cache.c
new file mode 100644
index 00000000000..f0af0ede9b1
--- /dev/null
+++ b/source/blender/blenkernel/intern/editmesh_cache.c
@@ -0,0 +1,120 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/editmesh_cache.c
+ * \ingroup bke
+ *
+ * Manage edit mesh cache: #EditMeshData
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_cache.h" /* own include */
+
+void BKE_editmesh_cache_ensure_poly_normals(BMEditMesh *em, EditMeshData *emd)
+{
+ if (!(emd->vertexCos && (emd->polyNos == NULL))) {
+ return;
+ }
+
+ BMesh *bm = em->bm;
+ const float (*vertexCos)[3];
+ float (*polyNos)[3];
+
+ BMFace *efa;
+ BMIter fiter;
+ int i;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ polyNos = MEM_mallocN(sizeof(*polyNos) * bm->totface, __func__);
+
+ vertexCos = emd->vertexCos;
+
+ BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_elem_index_set(efa, i); /* set_inline */
+ BM_face_calc_normal_vcos(bm, efa, polyNos[i], vertexCos);
+ }
+ bm->elem_index_dirty &= ~BM_FACE;
+
+ emd->polyNos = (const float (*)[3])polyNos;
+}
+
+void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh *em, EditMeshData *emd)
+{
+ if (!(emd->vertexCos && (emd->vertexNos == NULL))) {
+ return;
+ }
+
+ BMesh *bm = em->bm;
+ const float (*vertexCos)[3], (*polyNos)[3];
+ float (*vertexNos)[3];
+
+ /* calculate vertex normals from poly normals */
+ BKE_editmesh_cache_ensure_poly_normals(em, emd);
+
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ polyNos = emd->polyNos;
+ vertexCos = emd->vertexCos;
+ vertexNos = MEM_callocN(sizeof(*vertexNos) * bm->totvert, __func__);
+
+ BM_verts_calc_normal_vcos(bm, polyNos, vertexCos, vertexNos);
+
+ emd->vertexNos = (const float (*)[3])vertexNos;
+}
+
+void BKE_editmesh_cache_ensure_poly_centers(BMEditMesh *em, EditMeshData *emd)
+{
+ if (emd->polyCos != NULL) {
+ return;
+ }
+ BMesh *bm = em->bm;
+ float (*polyCos)[3];
+
+ BMFace *efa;
+ BMIter fiter;
+ int i;
+
+ polyCos = MEM_mallocN(sizeof(*polyCos) * bm->totface, __func__);
+
+ if (emd->vertexCos) {
+ const float (*vertexCos)[3];
+ vertexCos = emd->vertexCos;
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_face_calc_center_mean_vcos(bm, efa, polyCos[i], vertexCos);
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (efa, &fiter, bm, BM_FACES_OF_MESH, i) {
+ BM_face_calc_center_mean(efa, polyCos[i]);
+ }
+ }
+
+ emd->polyCos = (const float (*)[3])polyCos;
+}
diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c
new file mode 100644
index 00000000000..4231ad54ea8
--- /dev/null
+++ b/source/blender/blenkernel/intern/editmesh_tangent.c
@@ -0,0 +1,433 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/editmesh_tangent.c
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_defs.h"
+#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h" /* for utility functions */
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_tangent.h"
+
+#include "MEM_guardedalloc.h"
+
+/* interface */
+#include "mikktspace.h"
+
+/** \name Tangent Space Calculation
+ * \{ */
+
+/* Necessary complexity to handle looptri's as quads for correct tangents */
+#define USE_LOOPTRI_DETECT_QUADS
+
+typedef struct {
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const BMLoop *(*looptris)[3];
+ int cd_loop_uv_offset; /* texture coordinates */
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
+#endif
+
+} SGLSLEditMeshToTangent;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+/* seems weak but only used on quads */
+static const BMLoop *bm_loop_at_face_index(const BMFace *f, int vert_index)
+{
+ const BMLoop *l = BM_FACE_FIRST_LOOP(f);
+ while (vert_index--) {
+ l = l->next;
+ }
+ return l;
+}
+#endif
+
+static int emdm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ return pMesh->num_face_as_quad_map;
+#else
+ return pMesh->numTessFaces;
+#endif
+}
+
+static int emdm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const BMLoop **lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ return 4;
+ }
+ }
+ return 3;
+#else
+ UNUSED_VARS(pContext, face_num);
+ return 3;
+#endif
+}
+
+static void emdm_ts_GetPosition(
+ const SMikkTSpaceContext *pContext, float r_co[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+ const float *co;
+
+finally:
+ co = l->v->co;
+ copy_v3_v3(r_co, co);
+}
+
+static void emdm_ts_GetTextureCoordinate(
+ const SMikkTSpaceContext *pContext, float r_uv[2],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+finally:
+ if (pMesh->cd_loop_uv_offset != -1) {
+ const float *uv = BM_ELEM_CD_GET_VOID_P(l, pMesh->cd_loop_uv_offset);
+ copy_v2_v2(r_uv, uv);
+ }
+ else {
+ const float *orco = pMesh->orco[BM_elem_index_get(l->v)];
+ map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+ }
+}
+
+static void emdm_ts_GetNormal(
+ const SMikkTSpaceContext *pContext, float r_no[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+finally:
+ if (pMesh->precomputedLoopNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[BM_elem_index_get(l)]);
+ }
+ else if (BM_elem_flag_test(l->f, BM_ELEM_SMOOTH) == 0) { /* flat */
+ if (pMesh->precomputedFaceNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedFaceNormals[BM_elem_index_get(l->f)]);
+ }
+ else {
+ copy_v3_v3(r_no, l->f->no);
+ }
+ }
+ else {
+ copy_v3_v3(r_no, l->v->no);
+ }
+}
+
+static void emdm_ts_SetTSpace(
+ const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLEditMeshToTangent *pMesh = pContext->m_pUserData;
+ const BMLoop **lt;
+ const BMLoop *l;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = pMesh->looptris[pMesh->face_as_quad_map[face_num]];
+ if (lt[0]->f->len == 4) {
+ l = bm_loop_at_face_index(lt[0]->f, vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = pMesh->looptris[face_num];
+ }
+#else
+ lt = pMesh->looptris[face_num];
+#endif
+ l = lt[vert_index];
+
+ float *pRes;
+
+finally:
+ pRes = pMesh->tangent[BM_elem_index_get(l)];
+ copy_v3_v3(pRes, fvTangent);
+ pRes[3] = fSign;
+}
+
+static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
+ /* new computation method */
+ {
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+ sContext.m_pUserData = mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = emdm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = emdm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = emdm_ts_GetPosition;
+ sInterface.m_getTexCoord = emdm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = emdm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = emdm_ts_SetTSpace;
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
+}
+
+/**
+ * \see #BKE_mesh_calc_loop_tangent, same logic but used arrays instead of #BMesh data.
+ *
+ * \note This function is not so normal, its using `bm->ldata` as input, but output's to `dm->loopData`.
+ * This is done because #CD_TANGENT is cache data used only for drawing.
+ */
+void BKE_editmesh_loop_tangent_calc(
+ BMEditMesh *em, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p)
+{
+ BMesh *bm = em->bm;
+
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ short tangent_mask = 0;
+ short tangent_mask_curr = *tangent_mask_curr_p;
+
+ BKE_mesh_calc_loop_tangent_step_0(
+ &bm->ldata, calc_active_tangent, tangent_names, tangent_names_len,
+ &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+
+ if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
+ for (int i = 0; i < tangent_names_len; i++) {
+ if (tangent_names[i][0]) {
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ &bm->ldata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
+ }
+ }
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
+ if (calc_act && act_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(&bm->ldata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
+ int totface = em->tottri;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (em->tottri != bm->totface) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * totface, __func__);
+ int i, j;
+ for (i = 0, j = 0; j < totface; i++, j++) {
+ face_as_quad_map[i] = j;
+ /* step over all quads */
+ if (em->looptris[j][0]->f->len == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = i;
+ }
+ else {
+ num_face_as_quad_map = totface;
+ }
+#endif
+ /* Calculation */
+ if (em->tottri != 0) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ tangent_mask_curr = 0;
+ /* Calculate tangent layers */
+ SGLSLEditMeshToTangent data_array[MAX_MTFACE];
+ int index = 0;
+ int n = 0;
+ CustomData_update_typemap(loopdata_out);
+ const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
+ for (n = 0; n < tangent_layer_num; n++) {
+ index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLEditMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = em->tottri;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+#endif
+ mesh2tangent->precomputedFaceNormals = poly_normals;
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = loop_normals;
+ mesh2tangent->cd_loop_uv_offset = CustomData_get_n_offset(&bm->ldata, CD_MLOOPUV, n);
+
+ /* needed for indexing loop-tangents */
+ int htype_index = BM_LOOP;
+ if (mesh2tangent->cd_loop_uv_offset == -1) {
+ mesh2tangent->orco = vert_orco;
+ if (!mesh2tangent->orco)
+ continue;
+ /* needed for orco lookups */
+ htype_index |= BM_VERT;
+ tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
+ }
+ else {
+ /* Fill the resulting tangent_mask */
+ int uv_ind = CustomData_get_named_layer_index(&bm->ldata, CD_MLOOPUV, loopdata_out->layers[index].name);
+ int uv_start = CustomData_get_layer_index(&bm->ldata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ tangent_mask_curr |= 1 << (uv_ind - uv_start);
+ }
+ if (mesh2tangent->precomputedFaceNormals) {
+ /* needed for face normal lookups */
+ htype_index |= BM_FACE;
+ }
+ BM_mesh_elem_index_ensure(bm, htype_index);
+
+ mesh2tangent->looptris = (const BMLoop *(*)[3])em->looptris;
+ mesh2tangent->tangent = loopdata_out->layers[index].data;
+
+ BLI_task_pool_push(task_pool, emDM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
+
+ BLI_assert(tangent_mask_curr == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
+ else {
+ tangent_mask_curr = tangent_mask;
+ }
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+#undef USE_LOOPTRI_DETECT_QUADS
+#endif
+ }
+
+ *tangent_mask_curr_p = tangent_mask_curr;
+
+ int act_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[act_uv_index].name);
+ CustomData_set_layer_active_index(loopdata_out, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
+
+ /* Update render layer index */
+ int ren_uv_index = CustomData_get_layer_index_n(&bm->ldata, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index >= 0) {
+ int tan_index = CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, bm->ldata.layers[ren_uv_index].name);
+ CustomData_set_layer_render_index(loopdata_out, CD_TANGENT, tan_index);
+ } /* else tangent has been built from orco */
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 82bf65993a8..7c86c0722dc 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -37,9 +37,10 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
#include "DNA_listBase.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
@@ -57,13 +58,14 @@
#include "PIL_time.h"
#include "BKE_anim.h" /* needed for where_on_path */
+#include "BKE_bvhutils.h"
+#include "BKE_collection.h"
#include "BKE_collision.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -71,6 +73,9 @@
#include "BKE_scene.h"
#include "BKE_smoke.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
@@ -82,7 +87,7 @@
#include <string.h>
#endif // WITH_MOD_FLUID
-EffectorWeights *BKE_add_effector_weights(Group *group)
+EffectorWeights *BKE_add_effector_weights(Collection *collection)
{
EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights");
int i;
@@ -93,7 +98,7 @@ EffectorWeights *BKE_add_effector_weights(Group *group)
weights->global_gravity = 1.0f;
- weights->group = group;
+ weights->group = collection;
return weights;
}
@@ -107,6 +112,7 @@ PartDeflect *object_add_collision_fields(int type)
pd->pdef_sbdamp = 0.1f;
pd->pdef_sbift = 0.2f;
pd->pdef_sboft = 0.02f;
+ pd->pdef_cfrict = 5.0f;
pd->seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
pd->f_strength = 1.0f;
pd->f_damp = 1.0f;
@@ -127,14 +133,13 @@ PartDeflect *object_add_collision_fields(int type)
pd->f_flow = 1.0f;
break;
}
- pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION;
+ pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION | PFIELD_CLOTH_USE_CULLING;
return pd;
}
-/* ***************** PARTICLES ***************** */
+/************************ PARTICLES ***************************/
-/* -------------------------- Effectors ------------------ */
void free_partdeflect(PartDeflect *pd)
{
if (!pd) {
@@ -146,183 +151,195 @@ void free_partdeflect(PartDeflect *pd)
MEM_freeN(pd);
}
-static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
-{
- EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
- eff->scene = scene;
- eff->ob = ob;
- eff->psys = psys;
- eff->pd = pd;
- eff->frame = -1;
- return eff;
-}
-static void add_object_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src, bool for_simulation)
-{
- EffectorCache *eff = NULL;
+/******************** EFFECTOR RELATIONS ***********************/
- if (ob == ob_src) {
- return;
+static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *eff)
+{
+ float ctime = DEG_get_ctime(depsgraph);
+ uint cfra = (uint)(ctime >= 0 ? ctime : -ctime);
+ if (!eff->pd->rng) {
+ eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
+ }
+ else {
+ BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
}
- if (for_simulation) {
- if (weights->weight[ob->pd->forcefield] == 0.0f) {
- return;
- }
+ if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVE) {
+ Curve *cu = eff->ob->data;
+ if (cu->flag & CU_PATH) {
+ if (eff->ob->runtime.curve_cache == NULL || eff->ob->runtime.curve_cache->path == NULL || eff->ob->runtime.curve_cache->path->data == NULL)
+ BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, 0);
- if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal) {
- return;
+ if (eff->ob->runtime.curve_cache->path && eff->ob->runtime.curve_cache->path->data) {
+ where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
+ mul_m4_v3(eff->ob->obmat, eff->guide_loc);
+ mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
+ }
}
}
+ else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
+ eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface);
+ if (eff->ob->type == OB_CURVE)
+ eff->flag |= PE_USE_NORMAL_DATA;
+ }
+ else if (eff->psys)
+ psys_update_particle_tree(eff->psys, ctime);
- if (*effectors == NULL)
- *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
+ /* Store object velocity */
+ if (eff->ob) {
+ float old_vel[3];
- eff = new_effector_cache(scene, ob, NULL, ob->pd);
+ BKE_object_where_is_calc_time(depsgraph, eff->scene, eff->ob, cfra - 1.0f);
+ copy_v3_v3(old_vel, eff->ob->obmat[3]);
+ BKE_object_where_is_calc_time(depsgraph, eff->scene, eff->ob, cfra);
+ sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel);
+ }
+}
- /* make sure imat is up to date */
- invert_m4_m4(ob->imat, ob->obmat);
+static void add_effector_relation(ListBase *relations, Object *ob, ParticleSystem *psys, PartDeflect *pd)
+{
+ EffectorRelation *relation = MEM_callocN(sizeof(EffectorRelation), "EffectorRelation");
+ relation->ob = ob;
+ relation->psys = psys;
+ relation->pd = pd;
- BLI_addtail(*effectors, eff);
+ BLI_addtail(relations, relation);
}
-static void add_particles_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src, bool for_simulation)
-{
- ParticleSettings *part = psys->part;
- if (!psys_check_enabled(ob, psys, G.is_rendering)) {
- return;
- }
- if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) {
- return;
- }
- if (part->pd && part->pd->forcefield && (!for_simulation || weights->weight[part->pd->forcefield] != 0.0f)) {
- if (*effectors == NULL) {
- *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
- }
- BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd));
+static void add_effector_evaluation(ListBase **effectors, Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
+{
+ if (*effectors == NULL) {
+ *effectors = MEM_callocN(sizeof(ListBase), "effector effectors");
}
- if (part->pd2 && part->pd2->forcefield && (!for_simulation || weights->weight[part->pd2->forcefield] != 0.0f)) {
- if (*effectors == NULL) {
- *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
- }
- BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd2));
- }
+ EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
+ eff->depsgraph = depsgraph;
+ eff->scene = scene;
+ eff->ob = ob;
+ eff->psys = psys;
+ eff->pd = pd;
+ eff->frame = -1;
+ BLI_addtail(*effectors, eff);
+
+ precalculate_effector(depsgraph, eff);
}
-/* returns ListBase handle with objects taking part in the effecting */
-ListBase *pdInitEffectors(
- Scene *scene, Object *ob_src, ParticleSystem *psys_src,
- EffectorWeights *weights, bool for_simulation)
+/* Create list of effector relations in the collection or entire scene.
+ * This is used by the depsgraph to build relations, as well as faster
+ * lookup of effectors during evaluation. */
+ListBase *BKE_effector_relations_create(
+ Depsgraph *depsgraph,
+ ViewLayer *view_layer,
+ Collection *collection)
{
- const uint layer = ob_src->lay;
- ListBase *effectors = NULL;
+ Base *base = BKE_collection_or_layer_objects(view_layer, collection);
+ const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
- if (weights->group) {
- for (GroupObject *go = weights->group->gobject.first; go; go = go->next) {
- if ((go->ob->lay & layer)) {
- if (go->ob->pd && go->ob->pd->forcefield) {
- add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src, for_simulation);
- }
+ ListBase *relations = MEM_callocN(sizeof(ListBase), "effector relations");
- if (go->ob->particlesystem.first) {
- for (ParticleSystem *psys = go->ob->particlesystem.first; psys; psys = psys->next) {
- add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src, for_simulation);
- }
- }
- }
+ for (; base; base = base->next) {
+ if (!(base->flag & base_flag)) {
+ continue;
}
- }
- else {
- for (Base *base = scene->base.first; base; base = base->next) {
- if ((base->lay & layer)) {
- if (base->object->pd && base->object->pd->forcefield) {
- add_object_to_effectors(&effectors, scene, weights, base->object, ob_src, for_simulation);
+
+ Object *ob = base->object;
+
+ if (ob->pd && ob->pd->forcefield) {
+ add_effector_relation(relations, ob, NULL, ob->pd);
+ }
+
+ for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
+
+ if (psys_check_enabled(ob, psys, for_render)) {
+ if (part->pd && part->pd->forcefield) {
+ add_effector_relation(relations, ob, psys, part->pd);
}
- if (base->object->particlesystem.first) {
- for (ParticleSystem *psys = base->object->particlesystem.first; psys; psys = psys->next) {
- add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src, for_simulation);
- }
+ if (part->pd2 && part->pd2->forcefield) {
+ add_effector_relation(relations, ob, psys, part->pd2);
}
}
}
}
- if (for_simulation) {
- pdPrecalculateEffectors(effectors);
- }
-
- return effectors;
+ return relations;
}
-void pdEndEffectors(ListBase **effectors)
+void BKE_effector_relations_free(ListBase *lb)
{
- if (*effectors) {
- for (EffectorCache *eff = (*effectors)->first; eff; eff = eff->next) {
- if (eff->guide_data) {
- MEM_freeN(eff->guide_data);
- }
- }
-
- BLI_freelistN(*effectors);
- MEM_freeN(*effectors);
- *effectors = NULL;
+ if (lb) {
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
}
}
-static void precalculate_effector(EffectorCache *eff)
+/* Create effective list of effectors from relations built beforehand. */
+ListBase *BKE_effectors_create(
+ Depsgraph *depsgraph,
+ Object *ob_src,
+ ParticleSystem *psys_src,
+ EffectorWeights *weights)
{
- uint cfra = (uint)(eff->scene->r.cfra >= 0 ? eff->scene->r.cfra : -eff->scene->r.cfra);
- if (!eff->pd->rng) {
- eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
- }
- else {
- BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ ListBase *relations = DEG_get_effector_relations(depsgraph, weights->group);
+ ListBase *effectors = NULL;
+
+ if (!relations) {
+ return NULL;
}
- if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVE) {
- Curve *cu = eff->ob->data;
- if (cu->flag & CU_PATH) {
- if ((eff->ob->curve_cache == NULL) ||
- (eff->ob->curve_cache->path == NULL) ||
- (eff->ob->curve_cache->path->data == NULL))
- {
- BKE_displist_make_curveTypes(eff->scene, eff->ob, 0);
+ for (EffectorRelation *relation = relations->first; relation; relation = relation->next) {
+ /* Get evaluated object. */
+ Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
+
+ if (relation->psys) {
+ /* Get evaluated particle system. */
+ ParticleSystem *psys = BLI_findstring(&ob->particlesystem,
+ relation->psys->name, offsetof(ParticleSystem, name));
+ ParticleSettings *part = psys->part;
+
+ if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) {
+ continue;
}
- if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) {
- where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL);
- mul_m4_v3(eff->ob->obmat, eff->guide_loc);
- mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir);
+ PartDeflect *pd = (relation->pd == relation->psys->part->pd) ? part->pd : part->pd2;
+ if (weights->weight[pd->forcefield] == 0.0f) {
+ continue;
}
+
+ add_effector_evaluation(&effectors, depsgraph, scene, ob, psys, pd);
}
- }
- else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
- eff->surmd = (SurfaceModifierData *)modifiers_findByType(eff->ob, eModifierType_Surface);
- if (eff->ob->type == OB_CURVE) {
- eff->flag |= PE_USE_NORMAL_DATA;
+ else {
+ /* Object effector. */
+ if (ob == ob_src) {
+ continue;
+ }
+ else if (weights->weight[ob->pd->forcefield] == 0.0f) {
+ continue;
+ }
+ else if (ob->pd->shape == PFIELD_SHAPE_POINTS && ob->runtime.mesh_eval == NULL) {
+ continue;
+ }
+
+ add_effector_evaluation(&effectors, depsgraph, scene, ob, NULL, ob->pd);
}
}
- else if (eff->psys) {
- psys_update_particle_tree(eff->psys, eff->scene->r.cfra);
- }
- /* Store object velocity */
- if (eff->ob) {
- float old_vel[3];
-
- BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra - 1.0f);
- copy_v3_v3(old_vel, eff->ob->obmat[3]);
- BKE_object_where_is_calc_time(eff->scene, eff->ob, cfra);
- sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel);
- }
+ return effectors;
}
-void pdPrecalculateEffectors(ListBase *effectors)
+void BKE_effectors_free(ListBase *lb)
{
- if (effectors) {
- for (EffectorCache *eff = effectors->first; eff; eff = eff->next) {
- precalculate_effector(eff);
+ if (lb) {
+ for (EffectorCache *eff = lb->first; eff; eff = eff->next) {
+ if (eff->guide_data) {
+ MEM_freeN(eff->guide_data);
+ }
}
+
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
}
}
@@ -413,7 +430,7 @@ static float eff_calc_visibility(ListBase *colliders, EffectorCache *eff, Effect
return visibility;
}
if (!colls) {
- colls = get_collider_cache(eff->scene, eff->ob, NULL);
+ colls = BKE_collider_cache_create(eff->depsgraph, eff->ob, NULL);
}
if (!colls) {
return visibility;
@@ -453,7 +470,7 @@ static float eff_calc_visibility(ListBase *colliders, EffectorCache *eff, Effect
}
if (!colliders)
- free_collider_cache(&colls);
+ BKE_collider_cache_free(&colls);
return visibility;
}
@@ -534,7 +551,7 @@ float effector_falloff(EffectorCache *eff, EffectorData *efd, EffectedPoint *UNU
if (falloff == 0.0f)
break;
- r_fac = RAD2DEGF(saacos(fac / len_v3(efd->vec_to_point)));
+ r_fac = RAD2DEGF(saacos(fac / len_v3(efd->vec_to_point2)));
falloff *= falloff_func_rad(eff->pd, r_fac);
break;
@@ -577,7 +594,7 @@ int closest_point_on_surface(SurfaceModifierData *surmd, const float co[3], floa
}
int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity)
{
- float cfra = eff->scene->r.cfra;
+ float cfra = DEG_get_ctime(eff->depsgraph);
int ret = 0;
/* In case surface object is in Edit mode when loading the .blend, surface modifier is never executed
@@ -596,12 +613,10 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
efd->size = 0.0f;
}
else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
-
- if (eff->ob->derivedFinal) {
- DerivedMesh *dm = eff->ob->derivedFinal;
-
- dm->getVertCo(dm, *efd->index, efd->loc);
- dm->getVertNo(dm, *efd->index, efd->nor);
+ Mesh *me_eval = eff->ob->runtime.mesh_eval;
+ if (me_eval != NULL) {
+ copy_v3_v3(efd->loc, me_eval->mvert[*efd->index].co);
+ normal_short_to_float_v3(efd->nor, me_eval->mvert[*efd->index].no);
mul_m4_v3(eff->ob->obmat, efd->loc);
mul_mat3_m4_v3(eff->ob->obmat, efd->nor);
@@ -624,6 +639,7 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
}
else {
ParticleSimulationData sim = {NULL};
+ sim.depsgraph = eff->depsgraph;
sim.scene = eff->scene;
sim.ob = eff->ob;
sim.psys = eff->psys;
@@ -658,13 +674,13 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
/* use z-axis as normal*/
normalize_v3_v3(efd->nor, ob->obmat[2]);
- if (eff->pd && eff->pd->shape == PFIELD_SHAPE_PLANE) {
+ if (eff->pd && ELEM(eff->pd->shape, PFIELD_SHAPE_PLANE, PFIELD_SHAPE_LINE)) {
float temp[3], translate[3];
sub_v3_v3v3(temp, point->loc, ob->obmat[3]);
project_v3_v3v3(translate, temp, efd->nor);
/* for vortex the shape chooses between old / new force */
- if (eff->pd->forcefield == PFIELD_VORTEX) {
+ if (eff->pd->forcefield == PFIELD_VORTEX || eff->pd->shape == PFIELD_SHAPE_LINE) {
add_v3_v3v3(efd->loc, ob->obmat[3], translate);
}
else { /* normally efd->loc is closest point on effector xy-plane */
@@ -710,7 +726,8 @@ static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoin
efd->index = p;
if (eff->pd->shape == PFIELD_SHAPE_POINTS) {
- *tot = eff->ob->derivedFinal ? eff->ob->derivedFinal->numVertData : 1;
+ Mesh *me_eval = eff->ob->runtime.mesh_eval;
+ *tot = me_eval != NULL ? me_eval->totvert : 1;
if (*tot && eff->pd->forcefield == PFIELD_HARMONIC && point->index >= 0) {
*p = point->index % *tot;
@@ -893,7 +910,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
}
break;
case PFIELD_MAGNET:
- if (eff->pd->shape == PFIELD_SHAPE_POINT)
+ if (ELEM(eff->pd->shape, PFIELD_SHAPE_POINT, PFIELD_SHAPE_LINE))
/* magnetic field of a moving charge */
cross_v3_v3v3(temp, efd->nor, efd->vec_to_point);
else
@@ -988,7 +1005,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
}
}
-/* -------- pdDoEffectors() --------
+/* -------- BKE_effectors_apply() --------
* generic force/speed system, now used for particles and softbodies
* scene = scene where it runs in, for time and stuff
* lb = listbase with objects that take part in effecting
@@ -1001,7 +1018,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
* flags = only used for softbody wind now
* guide = old speed of particle
*/
-void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
+void BKE_effectors_apply(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
{
/*
* Modifies the force on a particle according to its
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 6ee6d877b9c..6deb7128b20 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -49,6 +49,8 @@
#include "BLI_threads.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
+#include "BLI_expr_pylike_eval.h"
+#include "BLI_alloca.h"
#include "BLT_translation.h"
@@ -65,6 +67,8 @@
#include "RNA_access.h"
+#include "atomic_ops.h"
+
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
@@ -882,25 +886,44 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample
* that the handles are correctly
*/
-/* Checks if the F-Curve has a Cycles modifier with simple settings that warrant transition smoothing */
-bool BKE_fcurve_is_cyclic(FCurve *fcu)
+/* Checks if the F-Curve has a Cycles modifier, and returns the type of the cycle behavior. */
+eFCU_Cycle_Type BKE_fcurve_get_cycle_type(FCurve *fcu)
{
FModifier *fcm = fcu->modifiers.first;
- if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES)
- return false;
+ if (!fcm || fcm->type != FMODIFIER_TYPE_CYCLES) {
+ return FCU_CYCLE_NONE;
+ }
- if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED))
- return false;
+ if (fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) {
+ return FCU_CYCLE_NONE;
+ }
- if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE))
- return false;
+ if (fcm->flag & (FMODIFIER_FLAG_RANGERESTRICT | FMODIFIER_FLAG_USEINFLUENCE)) {
+ return FCU_CYCLE_NONE;
+ }
FMod_Cycles *data = (FMod_Cycles *)fcm->data;
- return data && data->after_cycles == 0 && data->before_cycles == 0 &&
- ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) &&
- ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET);
+ if (data && data->after_cycles == 0 && data->before_cycles == 0) {
+ if (data->before_mode == FCM_EXTRAPOLATE_CYCLIC && data->after_mode == FCM_EXTRAPOLATE_CYCLIC) {
+ return FCU_CYCLE_PERFECT;
+ }
+
+ if (ELEM(data->before_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET) &&
+ ELEM(data->after_mode, FCM_EXTRAPOLATE_CYCLIC, FCM_EXTRAPOLATE_CYCLIC_OFFSET))
+ {
+ return FCU_CYCLE_OFFSET;
+ }
+ }
+
+ return FCU_CYCLE_NONE;
+}
+
+/* Checks if the F-Curve has a Cycles modifier with simple settings that warrant transition smoothing */
+bool BKE_fcurve_is_cyclic(FCurve *fcu)
+{
+ return BKE_fcurve_get_cycle_type(fcu) != FCU_CYCLE_NONE;
}
/* Shifts 'in' by the difference in coordinates between 'to' and 'from', using 'out' as the output buffer.
@@ -1288,31 +1311,6 @@ bool driver_get_variable_property(
return true;
}
-#if 0
-/* Helper function to obtain a pointer to a Pose Channel (for evaluating drivers) */
-static bPoseChannel *dtar_get_pchan_ptr(ChannelDriver *driver, DriverTarget *dtar)
-{
- ID *id;
- /* sanity check */
- if (ELEM(NULL, driver, dtar))
- return NULL;
-
- id = dtar_id_ensure_proxy_from(dtar->id);
-
- /* check if the ID here is a valid object */
- if (id && GS(id->name)) {
- Object *ob = (Object *)id;
-
- /* get pose, and subsequently, posechannel */
- return BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
- }
- else {
- /* cannot find a posechannel this way */
- return NULL;
- }
-}
-#endif
-
static short driver_check_valid_targets(ChannelDriver *driver, DriverVar *dvar)
{
short valid_targets = 0;
@@ -1694,11 +1692,8 @@ void driver_free_variable_ex(ChannelDriver *driver, DriverVar *dvar)
/* remove and free the driver variable */
driver_free_variable(&driver->variables, dvar);
-#ifdef WITH_PYTHON
/* since driver variables are cached, the expression needs re-compiling too */
- if (driver->type == DRIVER_TYPE_PYTHON)
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
-#endif
+ BKE_driver_invalidate_expression(driver, false, true);
}
/* Copy driver variables from src_vars list to dst_vars list */
@@ -1835,11 +1830,8 @@ DriverVar *driver_add_new_variable(ChannelDriver *driver)
/* set the default type to 'single prop' */
driver_change_variable_type(dvar, DVAR_TYPE_SINGLE_PROP);
-#ifdef WITH_PYTHON
/* since driver variables are cached, the expression needs re-compiling too */
- if (driver->type == DRIVER_TYPE_PYTHON)
- driver->flag |= DRIVER_FLAG_RENAMEVAR;
-#endif
+ BKE_driver_invalidate_expression(driver, false, true);
/* return the target */
return dvar;
@@ -1868,6 +1860,8 @@ void fcurve_free_driver(FCurve *fcu)
BPY_DECREF(driver->expr_comp);
#endif
+ BLI_expr_pylike_free(driver->expr_simple);
+
/* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
MEM_freeN(driver);
fcu->driver = NULL;
@@ -1885,6 +1879,7 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
/* copy all data */
ndriver = MEM_dupallocN(driver);
ndriver->expr_comp = NULL;
+ ndriver->expr_simple = NULL;
/* copy variables */
BLI_listbase_clear(&ndriver->variables); /* to get rid of refs to non-copied data (that's still used on original) */
@@ -1894,6 +1889,124 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
return ndriver;
}
+/* Driver Expression Evaluation --------------- */
+
+static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver)
+{
+ /* Prepare parameter names. */
+ int names_len = BLI_listbase_count(&driver->variables);
+ const char **names = BLI_array_alloca(names, names_len + 1);
+ int i = 0;
+
+ names[i++] = "frame";
+
+ for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ names[i++] = dvar->name;
+ }
+
+ return BLI_expr_pylike_parse(driver->expression, names, names_len + 1);
+}
+
+static bool driver_evaluate_simple_expr(ChannelDriver *driver, ExprPyLike_Parsed *expr, float *result, float time)
+{
+ /* Prepare parameter values. */
+ int vars_len = BLI_listbase_count(&driver->variables);
+ double *vars = BLI_array_alloca(vars, vars_len + 1);
+ int i = 0;
+
+ vars[i++] = time;
+
+ for (DriverVar *dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ vars[i++] = driver_get_variable_value(driver, dvar);
+ }
+
+ /* Evaluate expression. */
+ double result_val;
+ eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, vars, vars_len + 1, &result_val);
+ const char *message;
+
+ switch (status) {
+ case EXPR_PYLIKE_SUCCESS:
+ if (isfinite(result_val)) {
+ *result = (float)result_val;
+ }
+ return true;
+
+ case EXPR_PYLIKE_DIV_BY_ZERO:
+ case EXPR_PYLIKE_MATH_ERROR:
+ message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
+ fprintf(stderr, "\n%s in Driver: '%s'\n", message, driver->expression);
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ return true;
+
+ default:
+ /* arriving here means a bug, not user error */
+ printf("Error: simple driver expression evaluation failed: '%s'\n", driver->expression);
+ return false;
+ }
+}
+
+/* Compile and cache the driver expression if necessary, with thread safety. */
+static bool driver_compile_simple_expr(ChannelDriver *driver)
+{
+ if (driver->expr_simple != NULL) {
+ return true;
+ }
+
+ if (driver->type != DRIVER_TYPE_PYTHON) {
+ return false;
+ }
+
+ /* It's safe to parse in multiple threads; at worst it'll
+ * waste some effort, but in return avoids mutex contention. */
+ ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver);
+
+ /* Store the result if the field is still NULL, or discard
+ * it if another thread got here first. */
+ if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) {
+ BLI_expr_pylike_free(expr);
+ }
+
+ return true;
+}
+
+/* Try using the simple expression evaluator to compute the result of the driver.
+ * On success, stores the result and returns true; on failure result is set to 0. */
+static bool driver_try_evaluate_simple_expr(ChannelDriver *driver, ChannelDriver *driver_orig, float *result, float time)
+{
+ *result = 0.0f;
+
+ return driver_compile_simple_expr(driver_orig) &&
+ BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
+ driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
+}
+
+/* Check if the expression in the driver conforms to the simple subset. */
+bool BKE_driver_has_simple_expression(ChannelDriver *driver)
+{
+ return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
+}
+
+/* Reset cached compiled expression data */
+void BKE_driver_invalidate_expression(ChannelDriver *driver, bool expr_changed, bool varname_changed)
+{
+ if (expr_changed || varname_changed) {
+ BLI_expr_pylike_free(driver->expr_simple);
+ driver->expr_simple = NULL;
+ }
+
+#ifdef WITH_PYTHON
+ if (expr_changed) {
+ driver->flag |= DRIVER_FLAG_RECOMPILE;
+ }
+
+ if (varname_changed) {
+ driver->flag |= DRIVER_FLAG_RENAMEVAR;
+ }
+#endif
+}
+
/* Driver Evaluation -------------------------- */
/* Evaluate a Driver Variable to get a value that contributes to the final */
@@ -1922,13 +2035,14 @@ float driver_get_variable_value(ChannelDriver *driver, DriverVar *dvar)
/* Evaluate an Channel-Driver to get a 'time' value to use instead of "evaltime"
* - "evaltime" is the frame at which F-Curve is being evaluated
* - has to return a float value
+ * - driver_orig is where we cache Python expressions, in case of COW
*/
-float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const float evaltime)
+float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, ChannelDriver *driver_orig, const float evaltime)
{
DriverVar *dvar;
/* check if driver can be evaluated */
- if (driver->flag & DRIVER_FLAG_INVALID)
+ if (driver_orig->flag & DRIVER_FLAG_INVALID)
return 0.0f;
switch (driver->type) {
@@ -1996,26 +2110,26 @@ float evaluate_driver(PathResolvedRNA *anim_rna, ChannelDriver *driver, const fl
}
case DRIVER_TYPE_PYTHON: /* expression */
{
-#ifdef WITH_PYTHON
/* check for empty or invalid expression */
- if ( (driver->expression[0] == '\0') ||
- (driver->flag & DRIVER_FLAG_INVALID) )
+ if ( (driver_orig->expression[0] == '\0') ||
+ (driver_orig->flag & DRIVER_FLAG_INVALID) )
{
driver->curval = 0.0f;
}
- else {
+ else if (!driver_try_evaluate_simple_expr(driver, driver_orig, &driver->curval, evaltime)) {
+#ifdef WITH_PYTHON
/* this evaluates the expression using Python, and returns its result:
* - on errors it reports, then returns 0.0f
*/
BLI_mutex_lock(&python_driver_lock);
- driver->curval = BPY_driver_exec(anim_rna, driver, evaltime);
+ driver->curval = BPY_driver_exec(anim_rna, driver, driver_orig, evaltime);
BLI_mutex_unlock(&python_driver_lock);
- }
#else /* WITH_PYTHON*/
- UNUSED_VARS(anim_rna, evaltime);
+ UNUSED_VARS(anim_rna, evaltime);
#endif /* WITH_PYTHON*/
+ }
break;
}
default:
@@ -2187,24 +2301,6 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
}
}
-#if 0
-static void berekenx(float *f, float *o, int b)
-{
- float t, c0, c1, c2, c3;
- int a;
-
- c0 = f[0];
- c1 = 3.0f * (f[3] - f[0]);
- c2 = 3.0f * (f[0] - 2.0f * f[3] + f[6]);
- c3 = f[9] - f[0] + 3.0f * (f[3] - f[6]);
-
- for (a = 0; a < b; a++) {
- t = o[a];
- o[a] = c0 + t * c1 + t * t * c2 + t * t * t * c3;
- }
-}
-#endif
-
/* -------------------------- */
@@ -2705,7 +2801,7 @@ float evaluate_fcurve(FCurve *fcu, float evaltime)
return evaluate_fcurve_ex(fcu, evaltime, 0.0);
}
-float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
+float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, ChannelDriver *driver_orig, float evaltime)
{
BLI_assert(fcu->driver != NULL);
float cvalue = 0.0f;
@@ -2715,7 +2811,7 @@ float evaluate_fcurve_driver(PathResolvedRNA *anim_rna, FCurve *fcu, float evalt
*/
if (fcu->driver) {
/* evaltime now serves as input for the curve */
- evaltime = evaluate_driver(anim_rna, fcu->driver, evaltime);
+ evaltime = evaluate_driver(anim_rna, fcu->driver, driver_orig, evaltime);
/* only do a default 1-1 mapping if it's unlikely that anything else will set a value... */
if (fcu->totvert == 0) {
@@ -2762,7 +2858,7 @@ float calculate_fcurve(PathResolvedRNA *anim_rna, FCurve *fcu, float evaltime)
/* calculate and set curval (evaluates driver too if necessary) */
float curval;
if (fcu->driver) {
- curval = evaluate_fcurve_driver(anim_rna, fcu, evaltime);
+ curval = evaluate_fcurve_driver(anim_rna, fcu, fcu->driver, evaltime);
}
else {
curval = evaluate_fcurve(fcu, evaltime);
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index 0487302d9b6..bf1532bab42 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -30,46 +30,31 @@
*/
-// headers for fluidsim bobj meshes
-#include <stdlib.h>
-#include <zlib.h>
-#include <string.h>
-#include <stdio.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_object_fluidsim_types.h"
-#include "DNA_object_force_types.h" // for pointcache
#include "DNA_object_types.h"
-#include "DNA_particle_types.h"
-#include "DNA_scene_types.h"
#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_fluidsim.h"
-#include "BKE_modifier.h"
-#include "BKE_mesh.h"
+#include "BKE_library.h"
+#include "BKE_mesh_runtime.h"
/* ************************* fluidsim bobj file handling **************************** */
-
//-------------------------------------------------------------------------------
// file handling
//-------------------------------------------------------------------------------
-void initElbeemMesh(struct Scene *scene, struct Object *ob,
+void initElbeemMesh(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob,
int *numVertices, float **vertices,
int *numTriangles, int **triangles,
int useGlobalCoords, int modifierIndex)
{
- DerivedMesh *dm;
+ Mesh *mesh;
const MVert *mvert;
const MLoop *mloop;
const MLoopTri *looptri, *lt;
@@ -77,13 +62,13 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob,
float *verts;
int *tris;
- dm = mesh_create_derived_index_render(scene, ob, CD_MASK_BAREMESH, modifierIndex);
+ mesh = mesh_create_eval_final_index_render(depsgraph, scene, ob, CD_MASK_BAREMESH, modifierIndex);
- mvert = dm->getVertArray(dm);
- mloop = dm->getLoopArray(dm);
- looptri = dm->getLoopTriArray(dm);
- mvert_num = dm->getNumVerts(dm);
- looptri_num = dm->getNumLoopTri(dm);
+ mvert = mesh->mvert;
+ mloop = mesh->mloop;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ mvert_num = mesh->totvert;
+ looptri_num = mesh->runtime.looptris.len;
*numVertices = mvert_num;
verts = MEM_mallocN(mvert_num * sizeof(float[3]), "elbeemmesh_vertices");
@@ -102,5 +87,5 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob,
}
*triangles = tris;
- dm->release(dm);
+ BKE_id_free(NULL, mesh);
}
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index e288242ce9c..4fede89e9ca 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -835,27 +835,6 @@ static FModifierTypeInfo FMI_NOISE = {
NULL /* evaluate with storage */
};
-/* Filter F-Curve Modifier --------------------------- */
-
-#if 0 // XXX not yet implemented
-static FModifierTypeInfo FMI_FILTER = {
- FMODIFIER_TYPE_FILTER, /* type */
- sizeof(FMod_Filter), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- N_("Filter"), /* name */
- "FMod_Filter", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- NULL, /* new data */
- NULL /*fcm_filter_verify*/, /* verify */
- NULL, /* evaluate time */
- fcm_filter_evaluate, /* evaluate */
- NULL, /* evaluate time with storage */
- NULL /* evaluate with storage */
-};
-#endif // XXX not yet implemented
-
/* Python F-Curve Modifier --------------------------- */
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index e51b10a97a4..f6e1fabc6c0 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -635,6 +635,22 @@ struct TempLineInfo {
int wspace_nr; /* number of whitespaces of line */
};
+/**
+ * Font metric values explained:
+ *
+ * Baseline: Line where the text "rests", used as the origin vertical position for the glyphs.
+ * Em height: Space most glyphs should fit within.
+ * Ascent: the recommended distance above the baseline to fit most characters.
+ * Descent: the recommended distance below the baseline to fit most characters.
+ *
+ * We obtain ascent and descent from the font itself (FT_Face->ascender / face->height).
+ * And in some cases it is even the same value as FT_Face->bbox.yMax/yMin (font top and bottom respectively).
+ *
+ * The em_height here is relative to FT_Face->bbox.
+*/
+#define ASCENT(vfd) ((vfd)->ascender * (vfd)->em_height)
+#define DESCENT(vfd) ((vfd)->em_height - ASCENT(vfd))
+
bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
const wchar_t **r_text, int *r_text_len, bool *r_text_free,
struct CharTrans **r_chartransdata)
@@ -648,8 +664,6 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
bool use_textbox;
VChar *che;
struct CharTrans *chartransdata = NULL, *ct;
- /* Text at the beginning of the last used text-box (use for y-axis alignment). */
- int i_textbox = 0;
struct TempLineInfo *lineinfo;
float *f, xof, yof, xtrax, linedist;
float twidth, maxlen = 0;
@@ -663,6 +677,10 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
const float xof_scale = cu->xof / cu->fsize;
const float yof_scale = cu->yof / cu->fsize;
+ /* Text at the beginning of the last used text-box (use for y-axis alignment).
+ * We overallocate by one to simplify logic of getting last char. */
+ int *i_textbox_array = MEM_callocN(sizeof(*i_textbox_array) * (cu->totbox + 1), "TextBox initial char index");
+
#define MARGIN_X_MIN (xof_scale + tb_scale.x)
#define MARGIN_Y_MIN (yof_scale + tb_scale.y)
@@ -862,9 +880,9 @@ makebreak:
(cu->totbox > (curbox + 1)) &&
((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale))
{
- i_textbox = i + 1;
maxlen = 0;
curbox++;
+ i_textbox_array[curbox] = i + 1;
textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
@@ -1019,50 +1037,73 @@ makebreak:
/* top-baseline is default, in this case, do nothing */
if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
if (tb_scale.h != 0.0f) {
- /* top and top-baseline are the same when text-boxes are used */
- if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) {
- /* all previous textboxes are 'full', only align the last used text-box */
- float yoff;
+ /* We need to loop all the text-boxes even the "full" ones.
+ * This way they all get the same vertical padding. */
+ for (int tb_index = 0; tb_index < cu->totbox; tb_index++) {
+ struct CharTrans *ct_first, *ct_last;
+ const int i_textbox = i_textbox_array[tb_index];
+ const int i_textbox_next = i_textbox_array[tb_index + 1];
+ const bool is_last_filled_textbox = ELEM(i_textbox_next, 0, slen + 1);
int lines;
- struct CharTrans *ct_last, *ct_textbox;
- ct_last = chartransdata + slen - 1;
- ct_textbox = chartransdata + i_textbox;
+ ct_first = chartransdata + i_textbox;
+ ct_last = chartransdata + (is_last_filled_textbox ? slen: i_textbox_next - 1);
+ lines = ct_last->linenr - ct_first->linenr + 1;
- lines = ct_last->linenr - ct_textbox->linenr + 1;
- if (mem[slen - 1] == '\n') {
- lines++;
- }
+ textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / cu->fsize);
+ /* The initial Y origin of the textbox is hardcoded to 1.0f * text scale. */
+ const float textbox_y_origin = 1.0f;
+ float yoff = 0.0f;
- if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
- yoff = (lines * linedist) - tb_scale.h;
- }
- else if (cu->align_y == CU_ALIGN_Y_CENTER) {
- yoff = 0.5f * ((lines * linedist) - tb_scale.h);
+ switch (cu->align_y) {
+ case CU_ALIGN_Y_TOP_BASELINE:
+ break;
+ case CU_ALIGN_Y_TOP:
+ yoff = textbox_y_origin - ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_CENTER:
+ yoff = ((((vfd->em_height + (lines - 1) * linedist) * 0.5f) - ASCENT(vfd)) -
+ (tb_scale.h * 0.5f) + textbox_y_origin);
+ break;
+ case CU_ALIGN_Y_BOTTOM_BASELINE:
+ yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h;
+ break;
+ case CU_ALIGN_Y_BOTTOM:
+ yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h + DESCENT(vfd);
+ break;
}
- ct = ct_textbox;
- for (i = i_textbox - 1; i < slen; i++) {
+ for (ct = ct_first; ct <= ct_last; ct++) {
ct->yof += yoff;
- ct++;
+ }
+
+ if (is_last_filled_textbox) {
+ break;
}
}
}
else {
- /* non text-box case handled separately */
- ct = chartransdata;
- float yoff;
+ /* Non text-box case handled separately. */
+ float yoff = 0.0f;
- if (cu->align_y == CU_ALIGN_Y_TOP) {
- yoff = -linedist;
- }
- else if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
- yoff = (lnr - 1.0f) * linedist;
- }
- else if (cu->align_y == CU_ALIGN_Y_CENTER) {
- yoff = (lnr - 2.0f) * linedist * 0.5f;
+ switch (cu->align_y) {
+ case CU_ALIGN_Y_TOP_BASELINE:
+ break;
+ case CU_ALIGN_Y_TOP:
+ yoff = -ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_CENTER:
+ yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_BOTTOM_BASELINE:
+ yoff = (lnr - 1) * linedist;
+ break;
+ case CU_ALIGN_Y_BOTTOM:
+ yoff = (lnr - 1) * linedist + DESCENT(vfd);
+ break;
}
+ ct = chartransdata;
for (i = 0; i <= slen; i++) {
ct->yof += yoff;
ct++;
@@ -1071,12 +1112,13 @@ makebreak:
}
MEM_freeN(lineinfo);
+ MEM_freeN(i_textbox_array);
/* TEXT ON CURVE */
/* Note: Only OB_CURVE objects could have a path */
if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) {
- BLI_assert(cu->textoncurve->curve_cache != NULL);
- if (cu->textoncurve->curve_cache->path) {
+ BLI_assert(cu->textoncurve->runtime.curve_cache != NULL);
+ if (cu->textoncurve->runtime.curve_cache != NULL && cu->textoncurve->runtime.curve_cache->path != NULL) {
float distfac, imat[4][4], imat3[3][3], cmat[3][3];
float minx, maxx, miny, maxy;
float timeofs, sizefac;
@@ -1106,7 +1148,7 @@ makebreak:
/* we put the x-coordinaat exact at the curve, the y is rotated */
/* length correction */
- distfac = sizefac * cu->textoncurve->curve_cache->path->totdist / (maxx - minx);
+ distfac = sizefac * cu->textoncurve->runtime.curve_cache->path->totdist / (maxx - minx);
timeofs = 0.0f;
if (distfac > 1.0f) {
@@ -1190,13 +1232,13 @@ makebreak:
}
}
- if (mode == FO_CURSUP || mode == FO_CURSDOWN || mode == FO_PAGEUP || mode == FO_PAGEDOWN) {
+ if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN)) {
ct = &chartransdata[ef->pos];
- if ((mode == FO_CURSUP || mode == FO_PAGEUP) && ct->linenr == 0) {
+ if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) {
/* pass */
}
- else if ((mode == FO_CURSDOWN || mode == FO_PAGEDOWN) && ct->linenr == lnr) {
+ else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) {
/* pass */
}
else {
@@ -1339,6 +1381,8 @@ finally:
#undef MARGIN_Y_MIN
}
+#undef DESCENT
+#undef ASCENT
bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
{
@@ -1348,6 +1392,7 @@ bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
NULL, NULL, NULL, NULL);
}
+/** Warning: expects to have access to evaluated data (i.e. passed object should be evaluated one...). */
bool BKE_vfont_to_curve(Object *ob, int mode)
{
Curve *cu = ob->data;
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 686fe3bda93..57a2d2d4134 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -31,8 +31,8 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_freestyle_types.h"
-#include "DNA_group_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -61,17 +61,21 @@ void BKE_freestyle_config_init(FreestyleConfig *config)
BLI_listbase_clear(&config->linesets);
}
-void BKE_freestyle_config_free(FreestyleConfig *config)
+void BKE_freestyle_config_free(FreestyleConfig *config, const bool do_id_user)
{
FreestyleLineSet *lineset;
for (lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) {
if (lineset->group) {
- id_us_min(&lineset->group->id);
+ if (do_id_user) {
+ id_us_min(&lineset->group->id);
+ }
lineset->group = NULL;
}
if (lineset->linestyle) {
- id_us_min(&lineset->linestyle->id);
+ if (do_id_user) {
+ id_us_min(&lineset->linestyle->id);
+ }
lineset->linestyle = NULL;
}
}
@@ -79,7 +83,7 @@ void BKE_freestyle_config_free(FreestyleConfig *config)
BLI_freelistN(&config->modules);
}
-void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config, const int flag)
+void BKE_freestyle_config_copy(FreestyleConfig *new_config, const FreestyleConfig *config, const int flag)
{
FreestyleLineSet *lineset, *new_lineset;
FreestyleModuleConfig *module, *new_module;
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index e89508fd6c0..9c398182bb6 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -39,26 +39,84 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_math_color.h"
#include "BLI_string_utils.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
#include "BLT_translation.h"
+#include "DNA_anim_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_userdef_types.h"
#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "BKE_context.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
+#include "BKE_deform.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_colortools.h"
+#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_material.h"
+#include "DEG_depsgraph.h"
/* ************************************************** */
-/* GENERAL STUFF */
+/* Draw Engine */
-/* --------- Memory Management ------------ */
+void(*BKE_gpencil_batch_cache_dirty_tag_cb)(bGPdata *gpd) = NULL;
+void(*BKE_gpencil_batch_cache_free_cb)(bGPdata *gpd) = NULL;
+
+void BKE_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
+{
+ if (gpd) {
+ DEG_id_tag_update(&gpd->id, OB_RECALC_DATA);
+ BKE_gpencil_batch_cache_dirty_tag_cb(gpd);
+ }
+}
+
+void BKE_gpencil_batch_cache_free(bGPdata *gpd)
+{
+ if (gpd) {
+ BKE_gpencil_batch_cache_free_cb(gpd);
+ }
+}
+
+/* ************************************************** */
+/* Memory Management */
+
+/* clean vertex groups weights */
+void BKE_gpencil_free_point_weights(MDeformVert *dvert)
+{
+ if (dvert == NULL) {
+ return;
+ }
+ MEM_SAFE_FREE(dvert->dw);
+}
+
+void BKE_gpencil_free_stroke_weights(bGPDstroke *gps)
+{
+ if (gps == NULL) {
+ return;
+ }
+
+ if (gps->dvert == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *dvert = &gps->dvert[i];
+ BKE_gpencil_free_point_weights(dvert);
+ }
+}
/* free stroke, doesn't unlink from any listbase */
void BKE_gpencil_free_stroke(bGPDstroke *gps)
@@ -66,10 +124,14 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps)
if (gps == NULL) {
return;
}
-
/* free stroke memory arrays, then stroke itself */
- if (gps->points)
+ if (gps->points) {
MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
if (gps->triangles)
MEM_freeN(gps->triangles);
@@ -92,6 +154,24 @@ bool BKE_gpencil_free_strokes(bGPDframe *gpf)
return changed;
}
+/* Free strokes and colors belonging to a gp-frame */
+bool BKE_gpencil_free_frame_runtime_data(bGPDframe *derived_gpf)
+{
+ bGPDstroke *gps_next;
+ if (!derived_gpf) {
+ return false;
+ }
+
+ /* free strokes */
+ for (bGPDstroke *gps = derived_gpf->strokes.first; gps; gps = gps_next) {
+ gps_next = gps->next;
+ BKE_gpencil_free_stroke(gps);
+ }
+ BLI_listbase_clear(&derived_gpf->strokes);
+
+ return true;
+}
+
/* Free all of a gp-layer's frames */
void BKE_gpencil_free_frames(bGPDlayer *gpl)
{
@@ -111,101 +191,90 @@ void BKE_gpencil_free_frames(bGPDlayer *gpl)
gpl->actframe = NULL;
}
-/* Free all of a gp-colors */
-static void free_gpencil_colors(bGPDpalette *palette)
-{
- /* error checking */
- if (palette == NULL) {
- return;
- }
- /* free colors */
- BLI_freelistN(&palette->colors);
-}
-/* Free all of the gp-palettes and colors */
-void BKE_gpencil_free_palettes(ListBase *list)
+/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
+void BKE_gpencil_free_layers(ListBase *list)
{
- bGPDpalette *palette_next;
+ bGPDlayer *gpl_next;
/* error checking */
- if (list == NULL) {
- return;
- }
+ if (list == NULL) return;
- /* delete palettes */
- for (bGPDpalette *palette = list->first; palette; palette = palette_next) {
- palette_next = palette->next;
- /* free palette colors */
- free_gpencil_colors(palette);
+ /* delete layers */
+ for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
+ gpl_next = gpl->next;
- MEM_freeN(palette);
+ /* free layers and their data */
+ BKE_gpencil_free_frames(gpl);
+ BLI_freelinkN(list, gpl);
}
- BLI_listbase_clear(list);
}
-/* Free all of the gp-brushes for a viewport (list should be &gpd->brushes or so) */
-void BKE_gpencil_free_brushes(ListBase *list)
+/* clear all runtime derived data */
+static void BKE_gpencil_clear_derived(bGPDlayer *gpl)
{
- bGPDbrush *brush_next;
-
- /* error checking */
- if (list == NULL) {
+ if (gpl->runtime.derived_array == NULL) {
return;
}
- /* delete brushes */
- for (bGPDbrush *brush = list->first; brush; brush = brush_next) {
- brush_next = brush->next;
- /* free curves */
- if (brush->cur_sensitivity) {
- curvemapping_free(brush->cur_sensitivity);
- }
- if (brush->cur_strength) {
- curvemapping_free(brush->cur_strength);
- }
- if (brush->cur_jitter) {
- curvemapping_free(brush->cur_jitter);
- }
-
- MEM_freeN(brush);
+ for (int i = 0; i < gpl->runtime.len_derived; i++) {
+ bGPDframe *derived_gpf = &gpl->runtime.derived_array[i];
+ BKE_gpencil_free_frame_runtime_data(derived_gpf);
+ derived_gpf = NULL;
}
- BLI_listbase_clear(list);
+ gpl->runtime.len_derived = 0;
+ MEM_SAFE_FREE(gpl->runtime.derived_array);
}
-/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
-void BKE_gpencil_free_layers(ListBase *list)
+/* Free all of the gp-layers temp data*/
+static void BKE_gpencil_free_layers_temp_data(ListBase *list)
{
bGPDlayer *gpl_next;
/* error checking */
if (list == NULL) return;
-
/* delete layers */
for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) {
gpl_next = gpl->next;
+ BKE_gpencil_clear_derived(gpl);
+ }
+}
- /* free layers and their data */
- BKE_gpencil_free_frames(gpl);
- BLI_freelinkN(list, gpl);
+/* Free temp gpf derived frames */
+void BKE_gpencil_free_derived_frames(bGPdata *gpd)
+{
+ /* error checking */
+ if (gpd == NULL) return;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ BKE_gpencil_clear_derived(gpl);
}
}
/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */
-void BKE_gpencil_free(bGPdata *gpd, bool free_palettes)
+void BKE_gpencil_free(bGPdata *gpd, bool free_all)
{
+ /* clear animation data */
BKE_animdata_free(&gpd->id, false);
/* free layers */
+ if (free_all) {
+ BKE_gpencil_free_layers_temp_data(&gpd->layers);
+ }
BKE_gpencil_free_layers(&gpd->layers);
- /* free palettes */
- if (free_palettes) {
- BKE_gpencil_free_palettes(&gpd->palettes);
+ /* materials */
+ MEM_SAFE_FREE(gpd->mat);
+
+ /* free all data */
+ if (free_all) {
+ /* clear cache */
+ BKE_gpencil_batch_cache_free(gpd);
}
}
-/* -------- Container Creation ---------- */
+/* ************************************************** */
+/* Container Creation */
/* add a new gp-frame to the given layer */
bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe)
@@ -317,7 +386,8 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe)
/* add a new gp-layer and make it the active layer */
bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setactive)
{
- bGPDlayer *gpl;
+ bGPDlayer *gpl = NULL;
+ bGPDlayer *gpl_active = NULL;
/* check that list is ok */
if (gpd == NULL)
@@ -326,31 +396,42 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
/* allocate memory for frame and add to end of list */
gpl = MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
- /* add to datablock */
- BLI_addtail(&gpd->layers, gpl);
-
- /* set basic settings */
- copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
- /* Since GPv2 thickness must be 0 */
- gpl->thickness = 0;
+ gpl_active = BKE_gpencil_layer_getactive(gpd);
- gpl->opacity = 1.0f;
-
- /* onion-skinning settings */
- if (gpd->flag & GP_DATA_SHOW_ONIONSKINS)
- gpl->flag |= GP_LAYER_ONIONSKIN;
+ /* add to datablock */
+ if (gpl_active == NULL) {
+ BLI_addtail(&gpd->layers, gpl);
+ }
+ else {
+ /* if active layer, add after that layer */
+ BLI_insertlinkafter(&gpd->layers, gpl_active, gpl);
+ }
- gpl->flag |= (GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL);
+ /* annotation vs GP Object behaviour is slightly different */
+ if (gpd->flag & GP_DATA_ANNOTATIONS) {
+ /* set default color of new strokes for this layer */
+ copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
+ gpl->opacity = 1.0f;
- ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
- ARRAY_SET_ITEMS(gpl->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+ /* set default thickness of new strokes for this layer */
+ gpl->thickness = 3;
- /* high quality fill by default */
- gpl->flag |= GP_LAYER_HQ_FILL;
+ }
+ else {
+ /* thickness parameter represents "thickness change", not absolute thickness */
+ gpl->thickness = 0;
+ gpl->opacity = 1.0f;
+ /* onion-skinning settings */
+ gpl->onion_flag |= GP_LAYER_ONIONSKIN;
+ }
/* auto-name */
BLI_strncpy(gpl->info, name, sizeof(gpl->info));
- BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
+ BLI_uniquename(&gpd->layers, gpl,
+ (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"),
+ '.',
+ offsetof(bGPDlayer, info),
+ sizeof(gpl->info));
/* make this one the active one */
if (setactive)
@@ -360,292 +441,148 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti
return gpl;
}
-/* add a new gp-palette and make it the active */
-bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool setactive)
-{
- bGPDpalette *palette;
-
- /* check that list is ok */
- if (gpd == NULL) {
- return NULL;
- }
-
- /* allocate memory and add to end of list */
- palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette");
-
- /* add to datablock */
- BLI_addtail(&gpd->palettes, palette);
-
- /* set basic settings */
- /* auto-name */
- BLI_strncpy(palette->info, name, sizeof(palette->info));
- BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info),
- sizeof(palette->info));
-
- /* make this one the active one */
- /* NOTE: Always make this active if there's nothing else yet (T50123) */
- if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) {
- BKE_gpencil_palette_setactive(gpd, palette);
- }
-
- /* return palette */
- return palette;
-}
-
-/* create a set of default drawing brushes with predefined presets */
-void BKE_gpencil_brush_init_presets(ToolSettings *ts)
+/* add a new gp-datablock */
+bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
{
- bGPDbrush *brush;
- /* Basic brush */
- brush = BKE_gpencil_brush_addnew(ts, "Basic", true);
- brush->thickness = 3.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag |= ~GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
-
- brush->draw_smoothfac = 0.0f;
- brush->draw_smoothlvl = 1;
- brush->sublevel = 0;
- brush->draw_random_sub = 0.0f;
-
- /* Pencil brush */
- brush = BKE_gpencil_brush_addnew(ts, "Pencil", false);
- brush->thickness = 7.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 0.7f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
-
- brush->draw_smoothfac = 1.0f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
-
- /* Ink brush */
- brush = BKE_gpencil_brush_addnew(ts, "Ink", false);
- brush->thickness = 7.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.6f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
-
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
-
- brush->draw_random_press = 0.0f;
-
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ bGPdata *gpd;
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ /* allocate memory for a new block */
+ gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
- brush->draw_smoothfac = 1.1f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+ /* initial settings */
+ gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
- /* Ink Noise brush */
- brush = BKE_gpencil_brush_addnew(ts, "Ink noise", false);
- brush->thickness = 6.0f;
- brush->flag |= GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 1.611f;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
+ /* general flags */
+ gpd->flag |= GP_DATA_VIEWALIGN;
+ gpd->flag |= GP_DATA_STROKE_FORCE_RECALC;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ /* GP object specific settings */
+ ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f);
- brush->draw_random_press = 1.0f;
+ gpd->xray_mode = GP_XRAY_3DSPACE;
+ gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ /* grid settings */
+ ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color
+ ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale
+ gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ /* onion-skinning settings (datablock level) */
+ gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL);
+ gpd->onion_flag |= GP_ONION_FADE;
+ gpd->onion_mode = GP_ONION_MODE_RELATIVE;
+ gpd->onion_factor = 0.5f;
+ ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */
+ ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */
+ gpd->gstep = 1;
+ gpd->gstep_next = 1;
- brush->draw_smoothfac = 1.1f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+ return gpd;
+}
- /* Marker brush */
- brush = BKE_gpencil_brush_addnew(ts, "Marker", false);
- brush->thickness = 10.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 2.0f;
- brush->flag &= ~GP_BRUSH_USE_PRESSURE;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 1.0f;
- brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE;
+/* ************************************************** */
+/* Primitive Creation */
+/* Utilities for easier bulk-creation of geometry */
- brush->draw_random_press = 0.0f;
+/**
+ * Populate stroke with point data from data buffers
+ *
+ * \param array Flat array of point data values. Each entry has GP_PRIM_DATABUF_SIZE values
+ * \param mat 4x4 transform matrix to transform points into the right coordinate space
+ */
+void BKE_gpencil_stroke_add_points(bGPDstroke *gps, const float *array, const int totpoints, const float mat[4][4])
+{
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ const int x = GP_PRIM_DATABUF_SIZE * i;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ pt->x = array[x];
+ pt->y = array[x + 1];
+ pt->z = array[x + 2];
+ mul_m4_v3(mat, &pt->x);
- brush->draw_angle = M_PI_4; /* 45 degrees */
- brush->draw_angle_factor = 1.0f;
+ pt->pressure = array[x + 3];
+ pt->strength = array[x + 4];
+ }
+}
- brush->draw_smoothfac = 1.0f;
- brush->draw_smoothlvl = 2;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.0f;
+/* Create a new stroke, with pre-allocated data buffers */
+bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, short thickness)
+{
+ /* allocate memory for a new stroke */
+ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- /* Crayon brush */
- brush = BKE_gpencil_brush_addnew(ts, "Crayon", false);
- brush->thickness = 10.0f;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE;
- brush->draw_sensitivity = 3.0f;
- brush->flag &= ~GP_BRUSH_USE_PRESSURE;
+ gps->thickness = thickness * 25;
+ gps->inittime = 0;
- brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH;
- brush->draw_strength = 0.140f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
+ /* enable recalculation flag by default */
+ gps->flag = GP_STROKE_RECALC_CACHES | GP_STROKE_3DSPACE;
- brush->draw_random_press = 0.0f;
+ gps->totpoints = totpoints;
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
+ /* initialize triangle memory to dummy data */
+ gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation");
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
- brush->draw_angle = 0.0f;
- brush->draw_angle_factor = 0.0f;
+ gps->mat_nr = mat_idx;
- brush->draw_smoothfac = 0.0f;
- brush->draw_smoothlvl = 1;
- brush->sublevel = 2;
- brush->draw_random_sub = 0.5f;
+ /* add to frame */
+ BLI_addtail(&gpf->strokes, gps);
+ return gps;
}
-/* add a new gp-brush and make it the active */
-bGPDbrush *BKE_gpencil_brush_addnew(ToolSettings *ts, const char *name, bool setactive)
-{
- bGPDbrush *brush;
- /* check that list is ok */
- if (ts == NULL) {
- return NULL;
- }
-
- /* allocate memory and add to end of list */
- brush = MEM_callocN(sizeof(bGPDbrush), "bGPDbrush");
-
- /* add to datablock */
- BLI_addtail(&ts->gp_brushes, brush);
-
- /* set basic settings */
- brush->thickness = 3;
- brush->draw_smoothlvl = 1;
- brush->flag |= GP_BRUSH_USE_PRESSURE;
- brush->draw_sensitivity = 1.0f;
- brush->draw_strength = 1.0f;
- brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
- brush->draw_jitter = 0.0f;
- brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
-
- /* curves */
- brush->cur_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->cur_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- brush->cur_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
-
- /* auto-name */
- BLI_strncpy(brush->info, name, sizeof(brush->info));
- BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info));
+/* ************************************************** */
+/* Data Duplication */
- /* make this one the active one */
- if (setactive) {
- BKE_gpencil_brush_setactive(ts, brush);
+/* make a copy of a given gpencil weights */
+void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst)
+{
+ if (gps_src == NULL) {
+ return;
}
+ BLI_assert(gps_src->totpoints == gps_dst->totpoints);
- /* return brush */
- return brush;
+ BKE_defvert_array_copy(gps_dst->dvert, gps_src->dvert, gps_src->totpoints);
}
-/* add a new gp-palettecolor and make it the active */
-bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive)
+/* make a copy of a given gpencil stroke */
+bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src)
{
- bGPDpalettecolor *palcolor;
+ bGPDstroke *gps_dst = NULL;
- /* check that list is ok */
- if (palette == NULL) {
- return NULL;
- }
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->prev = gps_dst->next = NULL;
- /* allocate memory and add to end of list */
- palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor");
+ gps_dst->points = MEM_dupallocN(gps_src->points);
- /* add to datablock */
- BLI_addtail(&palette->colors, palcolor);
-
- /* set basic settings */
- palcolor->flag |= PC_COLOR_HQ_FILL;
- copy_v4_v4(palcolor->color, U.gpencil_new_layer_col);
- ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f);
-
- /* auto-name */
- BLI_strncpy(palcolor->info, name, sizeof(palcolor->info));
- BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info),
- sizeof(palcolor->info));
-
- /* make this one the active one */
- if (setactive) {
- BKE_gpencil_palettecolor_setactive(palette, palcolor);
+ if (gps_src->dvert != NULL) {
+ gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
+ }
+ else {
+ gps_dst->dvert = NULL;
}
- /* return palette color */
- return palcolor;
-}
-
-/* add a new gp-datablock */
-bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[])
-{
- bGPdata *gpd;
-
- /* allocate memory for a new block */
- gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0);
-
- /* initial settings */
- gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND);
-
- /* for now, stick to view is also enabled by default
- * since this is more useful...
+ /* Don't clear triangles, so that modifier evaluation can just use
+ * this without extra work first. Most places that need to force
+ * this data to get recalculated will destroy the data anyway though.
*/
- gpd->flag |= GP_DATA_VIEWALIGN;
+ gps_dst->triangles = MEM_dupallocN(gps_dst->triangles);
+ /* gps_dst->flag |= GP_STROKE_RECALC_CACHES; */
- return gpd;
+ /* return new stroke */
+ return gps_dst;
}
-/* -------- Data Duplication ---------- */
-
/* make a copy of a given gpencil frame */
bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
{
- bGPDstroke *gps_dst;
+ bGPDstroke *gps_dst = NULL;
bGPDframe *gpf_dst;
/* error checking */
@@ -660,11 +597,8 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
/* copy strokes */
BLI_listbase_clear(&gpf_dst->strokes);
for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke, then adjust pointer to points too */
- gps_dst = MEM_dupallocN(gps_src);
- gps_dst->points = MEM_dupallocN(gps_src->points);
- gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
- gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
@@ -672,55 +606,24 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src)
return gpf_dst;
}
-/* make a copy of a given gpencil brush */
-bGPDbrush *BKE_gpencil_brush_duplicate(const bGPDbrush *brush_src)
+/* make a copy of strokes between gpencil frames */
+void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst)
{
- bGPDbrush *brush_dst;
-
+ bGPDstroke *gps_dst = NULL;
/* error checking */
- if (brush_src == NULL) {
- return NULL;
- }
-
- /* make a copy of source brush */
- brush_dst = MEM_dupallocN(brush_src);
- brush_dst->prev = brush_dst->next = NULL;
- /* make a copy of curves */
- brush_dst->cur_sensitivity = curvemapping_copy(brush_src->cur_sensitivity);
- brush_dst->cur_strength = curvemapping_copy(brush_src->cur_strength);
- brush_dst->cur_jitter = curvemapping_copy(brush_src->cur_jitter);
-
- /* return new brush */
- return brush_dst;
-}
-
-/* make a copy of a given gpencil palette */
-bGPDpalette *BKE_gpencil_palette_duplicate(const bGPDpalette *palette_src)
-{
- bGPDpalette *palette_dst;
- const bGPDpalettecolor *palcolor_src;
- bGPDpalettecolor *palcolord_dst;
-
- /* error checking */
- if (palette_src == NULL) {
- return NULL;
+ if ((gpf_src == NULL) || (gpf_dst == NULL)) {
+ return;
}
- /* make a copy of source palette */
- palette_dst = MEM_dupallocN(palette_src);
- palette_dst->prev = palette_dst->next = NULL;
-
- /* copy colors */
- BLI_listbase_clear(&palette_dst->colors);
- for (palcolor_src = palette_src->colors.first; palcolor_src; palcolor_src = palcolor_src->next) {
- /* make a copy of source */
- palcolord_dst = MEM_dupallocN(palcolor_src);
- BLI_addtail(&palette_dst->colors, palcolord_dst);
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ /* make copy of source stroke */
+ gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
}
-
- /* return new palette */
- return palette_dst;
}
+
/* make a copy of a given gpencil layer */
bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
{
@@ -736,6 +639,8 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
/* make a copy of source layer */
gpl_dst = MEM_dupallocN(gpl_src);
gpl_dst->prev = gpl_dst->next = NULL;
+ gpl_dst->runtime.derived_array = NULL;
+ gpl_dst->runtime.len_derived = 0;
/* copy frames */
BLI_listbase_clear(&gpl_dst->frames);
@@ -755,14 +660,19 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src)
/**
* Only copy internal data of GreasePencil ID from source to already allocated/initialized destination.
- * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ * You probably never want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
*
* WARNING! This function will not handle ID user count!
*
* \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag))
+void BKE_gpencil_copy_data(bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag))
{
+ /* duplicate material array */
+ if (gpd_src->mat) {
+ gpd_dst->mat = MEM_dupallocN(gpd_src->mat);
+ }
+
/* copy layers */
BLI_listbase_clear(&gpd_dst->layers);
for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
@@ -771,45 +681,45 @@ void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata
BLI_addtail(&gpd_dst->layers, gpl_dst);
}
- /* copy palettes */
- BLI_listbase_clear(&gpd_dst->palettes);
- for (const bGPDpalette *palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) {
- bGPDpalette *palette_dst = BKE_gpencil_palette_duplicate(palette_src); /* TODO here too could add unused flags... */
- BLI_addtail(&gpd_dst->palettes, palette_dst);
- }
+}
+
+/* Standard API to make a copy of GP datablock, separate from copying its data */
+bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd)
+{
+ bGPdata *gpd_copy;
+ BKE_id_copy_ex(bmain, &gpd->id, (ID **)&gpd_copy, 0, false);
+ return gpd_copy;
}
/* make a copy of a given gpencil datablock */
+// XXX: Should this be deprecated?
bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy)
{
+ bGPdata *gpd_dst;
+
/* Yuck and super-uber-hyper yuck!!!
* Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it,
* so for now keep old code for that one. */
- if (internal_copy) {
- const bGPDlayer *gpl_src;
- bGPDlayer *gpl_dst;
- bGPdata *gpd_dst;
+ /* error checking */
+ if (gpd_src == NULL) {
+ return NULL;
+ }
+
+ if (internal_copy) {
/* make a straight copy for undo buffers used during stroke drawing */
gpd_dst = MEM_dupallocN(gpd_src);
-
- /* copy layers */
- BLI_listbase_clear(&gpd_dst->layers);
- for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
- /* make a copy of source layer and its data */
- gpl_dst = BKE_gpencil_layer_duplicate(gpl_src);
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- }
-
- /* return new */
- return gpd_dst;
}
else {
BLI_assert(bmain != NULL);
- bGPdata *gpd_copy;
- BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_copy, 0, false);
- return gpd_copy;
+ BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_dst, 0, false);
}
+
+ /* Copy internal data (layers, etc.) */
+ BKE_gpencil_copy_data(gpd_dst, gpd_src, 0);
+
+ /* return new */
+ return gpd_dst;
}
void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
@@ -817,7 +727,8 @@ void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local)
BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local);
}
-/* -------- GP-Stroke API --------- */
+/* ************************************************** */
+/* GP Stroke API */
/* ensure selection status of stroke is in sync with its points */
void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
@@ -842,7 +753,8 @@ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps)
}
}
-/* -------- GP-Frame API ---------- */
+/* ************************************************** */
+/* GP Frame API */
/* delete the last stroke of the given frame */
void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
@@ -855,18 +767,25 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf)
return;
/* free the stroke and its data */
- MEM_freeN(gps->points);
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
MEM_freeN(gps->triangles);
BLI_freelinkN(&gpf->strokes, gps);
/* if frame has no strokes after this, delete it */
if (BLI_listbase_is_empty(&gpf->strokes)) {
BKE_gpencil_layer_delframe(gpl, gpf);
- BKE_gpencil_layer_getframe(gpl, cfra, 0);
+ BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV);
}
}
-/* -------- GP-Layer API ---------- */
+/* ************************************************** */
+/* GP Layer API */
/* Check if the given layer is able to be edited or not */
bool gpencil_layer_is_editable(const bGPDlayer *gpl)
@@ -1048,8 +967,6 @@ bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
*/
if (gpl->actframe == gpf)
gpl->actframe = gpf->prev;
- else
- gpl->actframe = NULL;
/* free the frame and its data */
changed = BKE_gpencil_free_strokes(gpf);
@@ -1087,11 +1004,18 @@ void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
return;
/* loop over layers deactivating all */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next)
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
gpl->flag &= ~GP_LAYER_ACTIVE;
+ if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
+ gpl->flag |= GP_LAYER_LOCKED;
+ }
+ }
/* set as active one */
active->flag |= GP_LAYER_ACTIVE;
+ if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) {
+ active->flag &= ~GP_LAYER_LOCKED;
+ }
}
/* delete the active gp-layer */
@@ -1103,255 +1027,581 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl)
/* free layer */
BKE_gpencil_free_frames(gpl);
+
+ /* free icon providing preview of icon color */
+ BKE_icon_delete(gpl->runtime.icon_id);
+
+ /* free derived data */
+ BKE_gpencil_clear_derived(gpl);
+
BLI_freelinkN(&gpd->layers, gpl);
}
-/* ************************************************** */
-/* get the active gp-brush for editing */
-bGPDbrush *BKE_gpencil_brush_getactive(ToolSettings *ts)
+Material *BKE_gpencil_get_material_from_brush(Brush *brush)
{
- bGPDbrush *brush;
+ Material *ma = NULL;
- /* error checking */
- if (ELEM(NULL, ts, ts->gp_brushes.first)) {
- return NULL;
+ if ((brush != NULL) && (brush->gpencil_settings != NULL) &&
+ (brush->gpencil_settings->material != NULL))
+ {
+ ma = brush->gpencil_settings->material;
}
- /* loop over brushes until found (assume only one active) */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- if (brush->flag & GP_BRUSH_ACTIVE) {
- return brush;
+ return ma;
+}
+
+/* Get active color, and add all default settings if we don't find anything */
+Material *BKE_gpencil_material_ensure(Main *bmain, Object *ob)
+{
+ Material *ma = NULL;
+
+ /* sanity checks */
+ if (ELEM(NULL, bmain, ob))
+ return NULL;
+
+ ma = give_current_material(ob, ob->actcol);
+ if (ma == NULL) {
+ if (ob->totcol == 0) {
+ BKE_object_material_slot_add(bmain, ob);
}
+ ma = BKE_material_add_gpencil(bmain, DATA_("Material"));
+ assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF);
+ }
+ else if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
}
- /* no active brush found */
- return NULL;
+ return ma;
}
-/* set the active gp-brush */
-void BKE_gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active)
+/* ************************************************** */
+/* GP Object - Boundbox Support */
+
+/**
+ * Get min/max coordinate bounds for single stroke
+ * \return Returns whether we found any selected points
+ */
+bool BKE_gpencil_stroke_minmax(
+ const bGPDstroke *gps, const bool use_select,
+ float r_min[3], float r_max[3])
{
- bGPDbrush *brush;
+ const bGPDspoint *pt;
+ int i;
+ bool changed = false;
- /* error checking */
- if (ELEM(NULL, ts, ts->gp_brushes.first, active)) {
- return;
- }
+ if (ELEM(NULL, gps, r_min, r_max))
+ return false;
- /* loop over brushes deactivating all */
- for (brush = ts->gp_brushes.first; brush; brush = brush->next) {
- brush->flag &= ~GP_BRUSH_ACTIVE;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {
+ minmax_v3v3_v3(r_min, r_max, &pt->x);
+ changed = true;
+ }
}
-
- /* set as active one */
- active->flag |= GP_BRUSH_ACTIVE;
+ return changed;
}
-/* delete the active gp-brush */
-void BKE_gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush)
+/* get min/max bounds of all strokes in GP datablock */
+bool BKE_gpencil_data_minmax(Object *ob, const bGPdata *gpd, float r_min[3], float r_max[3])
{
- /* error checking */
- if (ELEM(NULL, ts, brush)) {
- return;
- }
+ float bmat[3][3];
+ bool changed = false;
+
+ INIT_MINMAX(r_min, r_max);
+
+ if (gpd == NULL)
+ return changed;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ bGPDframe *gpf = gpl->actframe;
- /* free curves */
- if (brush->cur_sensitivity) {
- curvemapping_free(brush->cur_sensitivity);
+ if (gpf != NULL) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ changed = BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
+ }
+ }
}
- if (brush->cur_strength) {
- curvemapping_free(brush->cur_strength);
+
+ if ((changed) && (ob)) {
+ copy_m3_m4(bmat, ob->obmat);
+ mul_m3_v3(bmat, r_min);
+ add_v3_v3(r_min, ob->obmat[3]);
+ mul_m3_v3(bmat, r_max);
+ add_v3_v3(r_max, ob->obmat[3]);
}
- if (brush->cur_jitter) {
- curvemapping_free(brush->cur_jitter);
+
+ return changed;
+}
+
+bool BKE_gpencil_stroke_select_check(
+ const bGPDstroke *gps)
+{
+ const bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (pt->flag & GP_SPOINT_SELECT) {
+ return true;
+ }
}
+ return false;
+}
+
+/* compute center of bounding box */
+void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
+{
+ float min[3], max[3], tot[3];
+
+ BKE_gpencil_data_minmax(NULL, gpd, min, max);
- /* free */
- BLI_freelinkN(&ts->gp_brushes, brush);
+ add_v3_v3v3(tot, min, max);
+ mul_v3_v3fl(r_centroid, tot, 0.5f);
}
-/* ************************************************** */
-/* get the active gp-palette for editing */
-bGPDpalette *BKE_gpencil_palette_getactive(bGPdata *gpd)
+
+/* create bounding box values */
+static void boundbox_gpencil(Object *ob)
{
- bGPDpalette *palette;
+ BoundBox *bb;
+ bGPdata *gpd;
+ float min[3], max[3];
- /* error checking */
- if (ELEM(NULL, gpd, gpd->palettes.first)) {
- return NULL;
+ if (ob->bb == NULL) {
+ ob->bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
}
- /* loop over palettes until found (assume only one active) */
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- if (palette->flag & PL_PALETTE_ACTIVE)
- return palette;
- }
+ bb = ob->bb;
+ gpd = ob->data;
- /* no active palette found */
- return NULL;
+ BKE_gpencil_data_minmax(NULL, gpd, min, max);
+ BKE_boundbox_init_from_minmax(bb, min, max);
+
+ bb->flag &= ~BOUNDBOX_DIRTY;
}
-/* set the active gp-palette */
-void BKE_gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active)
+/* get bounding box */
+BoundBox *BKE_gpencil_boundbox_get(Object *ob)
{
- bGPDpalette *palette;
+ bGPdata *gpd;
- /* error checking */
- if (ELEM(NULL, gpd, gpd->palettes.first, active)) {
- return;
- }
+ if (ELEM(NULL, ob, ob->data))
+ return NULL;
- /* loop over palettes deactivating all */
- for (palette = gpd->palettes.first; palette; palette = palette->next) {
- palette->flag &= ~PL_PALETTE_ACTIVE;
+ gpd = ob->data;
+ if ((ob->bb) && ((ob->bb->flag & BOUNDBOX_DIRTY) == 0) &&
+ ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0))
+ {
+ return ob->bb;
}
- /* set as active one */
- active->flag |= PL_PALETTE_ACTIVE;
- /* force color recalc */
- BKE_gpencil_palette_change_strokes(gpd);
+ boundbox_gpencil(ob);
+
+ return ob->bb;
}
-/* delete the active gp-palette */
-void BKE_gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette)
+/* ************************************************** */
+/* Apply Transforms */
+
+void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
{
- /* error checking */
- if (ELEM(NULL, gpd, palette)) {
+ if (gpd == NULL)
return;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* FIXME: For now, we just skip parented layers.
+ * Otherwise, we have to update each frame to find
+ * the current parent position/effects.
+ */
+ if (gpl->parent) {
+ continue;
+ }
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
+ for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) {
+ mul_m4_v3(mat, &pt->x);
+ }
+
+ /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+ }
+ }
}
- /* free colors */
- free_gpencil_colors(palette);
- BLI_freelinkN(&gpd->palettes, palette);
- /* force color recalc */
- BKE_gpencil_palette_change_strokes(gpd);
}
-/* Set all strokes to recalc the palette color */
-void BKE_gpencil_palette_change_strokes(bGPdata *gpd)
-{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
+/* ************************************************** */
+/* GP Object - Vertex Groups */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- gps->flag |= GP_STROKE_RECALC_COLOR;
+/* remove a vertex group */
+void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup)
+{
+ bGPdata *gpd = ob->data;
+ MDeformVert *dvert = NULL;
+ const int def_nr = BLI_findindex(&ob->defbase, defgroup);
+
+ /* Remove points data */
+ if (gpd) {
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->dvert != NULL) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ dvert = &gps->dvert[i];
+ MDeformWeight *dw = defvert_find_index(dvert, def_nr);
+ if (dw != NULL) {
+ defvert_remove_group(dvert, dw);
+ }
+ }
+ }
+ }
}
}
}
+
+ /* Remove the group */
+ BLI_freelinkN(&ob->defbase, defgroup);
+ DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
}
-/* get the active gp-palettecolor for editing */
-bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(bGPDpalette *palette)
+void BKE_gpencil_dvert_ensure(bGPDstroke *gps)
{
- bGPDpalettecolor *palcolor;
+ if (gps->dvert == NULL) {
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights");
+ }
+}
- /* error checking */
- if (ELEM(NULL, palette, palette->colors.first)) {
- return NULL;
+/* ************************************************** */
+
+/**
+ * Apply smooth to stroke point
+ * \param gps Stroke to smooth
+ * \param i Point index
+ * \param inf Amount of smoothing to apply
+ */
+bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf)
+{
+ bGPDspoint *pt = &gps->points[i];
+ // float pressure = 0.0f;
+ float sco[3] = { 0.0f };
+
+ /* Do nothing if not enough points to smooth out */
+ if (gps->totpoints <= 2) {
+ return false;
}
- /* loop over colors until found (assume only one active) */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- if (palcolor->flag & PC_COLOR_ACTIVE) {
- return palcolor;
+ /* Only affect endpoints by a fraction of the normal strength,
+ * to prevent the stroke from shrinking too much
+ */
+ if ((i == 0) || (i == gps->totpoints - 1)) {
+ inf *= 0.1f;
+ }
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
+ {
+ // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
+ const int steps = 2;
+ const float average_fac = 1.0f / (float)(steps * 2 + 1);
+ int step;
+
+ /* add the point itself */
+ madd_v3_v3fl(sco, &pt->x, average_fac);
+
+ /* n-steps before/after current point */
+ // XXX: review how the endpoints are treated by this algorithm
+ // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
+ for (step = 1; step <= steps; step++) {
+ bGPDspoint *pt1, *pt2;
+ int before = i - step;
+ int after = i + step;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pt1 = &gps->points[before];
+ pt2 = &gps->points[after];
+
+ /* add both these points to the average-sum (s += p[i]/n) */
+ madd_v3_v3fl(sco, &pt1->x, average_fac);
+ madd_v3_v3fl(sco, &pt2->x, average_fac);
+
}
}
- /* no active color found */
- return NULL;
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
+
+ return true;
}
-/* get the gp-palettecolor looking for name */
-bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name)
+
+/**
+ * Apply smooth for strength to stroke point */
+bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float influence)
{
- /* error checking */
- if (ELEM(NULL, palette, name)) {
- return NULL;
+ bGPDspoint *ptb = &gps->points[point_index];
+
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the strength
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ /* sometimes the factor can be wrong due stroke geometry, so use middle point */
+ if ((fac < 0.0f) || (fac > 1.0f)) {
+ fac = 0.5f;
}
+ const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength;
- return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info));
+ /* Based on influence factor, blend between original and optimal */
+ ptb->strength = (1.0f - influence) * ptb->strength + influence * optimal;
+
+ return true;
}
-/* Change color name in all strokes */
-void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname)
+/**
+ * Apply smooth for thickness to stroke point (use pressure) */
+bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float influence)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps;
+ bGPDspoint *ptb = &gps->points[point_index];
- /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
- if (ELEM(NULL, gpd, oldname, newname))
- return;
+ /* Do nothing if not enough points */
+ if ((gps->totpoints <= 2) || (point_index < 1)) {
+ return false;
+ }
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (STREQ(gps->colorname, oldname)) {
- BLI_strncpy(gps->colorname, newname, sizeof(gps->colorname));
- }
- }
- }
+ /* Compute theoretical optimal value using distances */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ /* sometimes the factor can be wrong due stroke geometry, so use middle point */
+ if ((fac < 0.0f) || (fac > 1.0f)) {
+ fac = 0.5f;
}
+ float optimal = interpf(ptc->pressure, pta->pressure, fac);
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->pressure = interpf(optimal, ptb->pressure, influence);
+ return true;
}
-/* Delete all strokes of the color */
-void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name)
+/**
+* Apply smooth for UV rotation to stroke point (use pressure) */
+bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influence)
{
- bGPDlayer *gpl;
- bGPDframe *gpf;
- bGPDstroke *gps, *gpsn;
+ bGPDspoint *ptb = &gps->points[point_index];
- /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */
- if (ELEM(NULL, gpd, name))
- return;
+ /* Do nothing if not enough points */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
-
- if (STREQ(gps->colorname, name)) {
- if (gps->points) MEM_freeN(gps->points);
- if (gps->triangles) MEM_freeN(gps->triangles);
- BLI_freelinkN(&gpf->strokes, gps);
- }
+ /* Compute theoretical optimal value */
+ bGPDspoint *pta, *ptc;
+ int before = point_index - 1;
+ int after = point_index + 1;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pta = &gps->points[before];
+ ptc = &gps->points[after];
+
+ /* the optimal value is the corresponding to the interpolation of the pressure
+ * at the distance of point b
+ */
+ float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
+ /* sometimes the factor can be wrong due stroke geometry, so use middle point */
+ if ((fac < 0.0f) || (fac > 1.0f)) {
+ fac = 0.5f;
+ }
+ float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac);
+
+ /* Based on influence factor, blend between original and optimal */
+ ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence);
+ CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2);
+
+ return true;
+}
+
+/**
+ * Get range of selected frames in layer.
+ * Always the active frame is considered as selected, so if no more selected the range
+ * will be equal to the current active frame.
+ * \param gpl Layer
+ * \param r_initframe Number of first selected frame
+ * \param r_endframe Number of last selected frame
+ */
+void BKE_gpencil_get_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe)
+{
+ *r_initframe = gpl->actframe->framenum;
+ *r_endframe = gpl->actframe->framenum;
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ if (gpf->flag & GP_FRAME_SELECT) {
+ if (gpf->framenum < *r_initframe) {
+ *r_initframe = gpf->framenum;
+ }
+ if (gpf->framenum > *r_endframe) {
+ *r_endframe = gpf->framenum;
}
}
}
+}
+/**
+ * Get Falloff factor base on frame range
+ * \param gpf Frame
+ * \param actnum Number of active frame in layer
+ * \param f_init Number of first selected frame
+ * \param f_end Number of last selected frame
+ * \param cur_falloff Curve with falloff factors
+ */
+float BKE_gpencil_multiframe_falloff_calc(bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff)
+{
+ float fnum = 0.5f; /* default mid curve */
+ float value;
+
+ /* check curve is available */
+ if (cur_falloff == NULL) {
+ return 1.0f;
+ }
+
+ /* frames to the right of the active frame */
+ if (gpf->framenum < actnum) {
+ fnum = (float)(gpf->framenum - f_init) / (actnum - f_init);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum);
+ }
+ /* frames to the left of the active frame */
+ else if (gpf->framenum > actnum) {
+ fnum = (float)(gpf->framenum - actnum) / (f_end - actnum);
+ fnum *= 0.5f;
+ value = curvemapping_evaluateF(cur_falloff, 0, fnum + 0.5f);
+ }
+ else {
+ value = 1.0f;
+ }
+
+ return value;
}
-/* set the active gp-palettecolor */
-void BKE_gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active)
+/* remove strokes using a material */
+void BKE_gpencil_material_index_remove(bGPdata *gpd, int index)
{
- bGPDpalettecolor *palcolor;
+ bGPDstroke *gps, *gpsn;
- /* error checking */
- if (ELEM(NULL, palette, palette->colors.first, active)) {
- return;
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->mat_nr == index) {
+ if (gps->points) {
+ MEM_freeN(gps->points);
+ }
+ if (gps->dvert) {
+ BKE_gpencil_free_stroke_weights(gps);
+ MEM_freeN(gps->dvert);
+ }
+ if (gps->triangles) MEM_freeN(gps->triangles);
+ BLI_freelinkN(&gpf->strokes, gps);
+ }
+ else {
+ /* reassign strokes */
+ if (gps->mat_nr > index) {
+ gps->mat_nr--;
+ }
+ }
+ }
+ }
+ }
+}
+
+void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len)
+{
+ const short remap_len_short = (short)remap_len;
+
+#define MAT_NR_REMAP(n) \
+ if (n < remap_len_short) { \
+ BLI_assert(n >= 0 && remap[n] < remap_len_short); \
+ n = remap[n]; \
+ } ((void)0)
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* reassign strokes */
+ MAT_NR_REMAP(gps->mat_nr);
+ }
+ }
}
- /* loop over colors deactivating all */
- for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
- palcolor->flag &= ~PC_COLOR_ACTIVE;
+#undef MAT_NR_REMAP
+
+}
+
+/* statistics functions */
+void BKE_gpencil_stats_update(bGPdata *gpd)
+{
+ gpd->totlayer = 0;
+ gpd->totframe = 0;
+ gpd->totstroke = 0;
+ gpd->totpoint = 0;
+
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpd->totlayer++;
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ gpd->totframe++;
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ gpd->totstroke++;
+ gpd->totpoint += gps->totpoints;
+ }
+ }
}
- /* set as active one */
- active->flag |= PC_COLOR_ACTIVE;
}
-/* delete the active gp-palettecolor */
-void BKE_gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor)
+/* get material index */
+int BKE_gpencil_get_material_index(Object *ob, Material *ma)
{
- /* error checking */
- if (ELEM(NULL, palette, palcolor)) {
- return;
+ short *totcol = give_totcolp(ob);
+ Material *read_ma = NULL;
+ for (short i = 0; i < *totcol; i++) {
+ read_ma = give_current_material(ob, i + 1);
+ if (ma == read_ma) {
+ return i + 1;
+ }
}
- /* free */
- BLI_freelinkN(&palette->colors, palcolor);
+ return 0;
}
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
new file mode 100644
index 00000000000..68691cd3d05
--- /dev/null
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -0,0 +1,826 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+ /** \file blender/blenkernel/intern/gpencil_modifier.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_gpencil_modifier_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_gpencil.h"
+#include "BKE_lattice.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_gpencil_modifiertypes.h"
+
+static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = { NULL };
+
+/* *************************************************** */
+/* Geometry Utilities */
+
+/* calculate stroke normal using some points */
+void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
+{
+ if (gps->totpoints < 3) {
+ zero_v3(r_normal);
+ return;
+ }
+
+ bGPDspoint *points = gps->points;
+ int totpoints = gps->totpoints;
+
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float vec1[3];
+ float vec2[3];
+
+ /* initial vector (p0 -> p1) */
+ sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(vec2, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(r_normal, vec1, vec2);
+
+ /* Normalize vector */
+ normalize_v3(r_normal);
+}
+
+/* Get points of stroke always flat to view not affected by camera view or view position */
+static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d)
+{
+ const bGPDspoint *pt0 = &points[0];
+ const bGPDspoint *pt1 = &points[1];
+ const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
+
+ float locx[3];
+ float locy[3];
+ float loc3[3];
+ float normal[3];
+
+ /* local X axis (p0 -> p1) */
+ sub_v3_v3v3(locx, &pt1->x, &pt0->x);
+
+ /* point vector at 3/4 */
+ sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
+
+ /* vector orthogonal to polygon plane */
+ cross_v3_v3v3(normal, locx, loc3);
+
+ /* local Y axis (cross to normal/x axis) */
+ cross_v3_v3v3(locy, normal, locx);
+
+ /* Normalize vectors */
+ normalize_v3(locx);
+ normalize_v3(locy);
+
+ /* Get all points in local space */
+ for (int i = 0; i < totpoints; i++) {
+ const bGPDspoint *pt = &points[i];
+ float loc[3];
+
+ /* Get local space using first point as origin */
+ sub_v3_v3v3(loc, &pt->x, &pt0->x);
+
+ vec2f *point = &points2d[i];
+ point->x = dot_v3v3(loc, locx);
+ point->y = dot_v3v3(loc, locy);
+ }
+
+}
+
+/* Stroke Simplify ------------------------------------- */
+
+/* Reduce a series of points to a simplified version, but
+ * maintains the general shape of the series
+ *
+ * Ramer - Douglas - Peucker algorithm
+ * by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
+ */
+static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon)
+{
+ vec2f *old_points2d = points2d;
+ int totpoints = gps->totpoints;
+ char *marked = NULL;
+ char work;
+
+ int start = 1;
+ int end = gps->totpoints - 2;
+
+ marked = MEM_callocN(totpoints, "GP marked array");
+ marked[start] = 1;
+ marked[end] = 1;
+
+ work = 1;
+ int totmarked = 0;
+ /* while still reducing */
+ while (work) {
+ int ls, le;
+ work = 0;
+
+ ls = start;
+ le = start + 1;
+
+ /* while not over interval */
+ while (ls < end) {
+ int max_i = 0;
+ float v1[2];
+ /* divided to get more control */
+ float max_dist = epsilon / 10.0f;
+
+ /* find the next marked point */
+ while (marked[le] == 0) {
+ le++;
+ }
+
+ /* perpendicular vector to ls-le */
+ v1[1] = old_points2d[le].x - old_points2d[ls].x;
+ v1[0] = old_points2d[ls].y - old_points2d[le].y;
+
+ for (int i = ls + 1; i < le; i++) {
+ float mul;
+ float dist;
+ float v2[2];
+
+ v2[0] = old_points2d[i].x - old_points2d[ls].x;
+ v2[1] = old_points2d[i].y - old_points2d[ls].y;
+
+ if (v2[0] == 0 && v2[1] == 0) {
+ continue;
+ }
+
+ mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
+
+ dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
+
+ if (dist > max_dist) {
+ max_dist = dist;
+ max_i = i;
+ }
+ }
+
+ if (max_i != 0) {
+ work = 1;
+ marked[max_i] = 1;
+ totmarked++;
+ }
+
+ ls = le;
+ le = ls + 1;
+ }
+ }
+
+ /* adding points marked */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = NULL;
+ MDeformVert *dvert_src = NULL;
+
+ if (gps->dvert != NULL) {
+ old_dvert = MEM_dupallocN(gps->dvert);
+ }
+ /* resize gps */
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+ if ((marked[i]) || (i == 0) || (i == totpoints - 1)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ if (dvert_src->dw) {
+ memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
+ }
+ }
+ j++;
+ }
+ else {
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+ MEM_SAFE_FREE(marked);
+}
+
+/* Simplify stroke using Ramer-Douglas-Peucker algorithm */
+void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor)
+{
+ /* first create temp data and convert points to 2D */
+ vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points");
+
+ gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d);
+
+ gpencil_rdp_stroke(gps, points2d, factor);
+
+ MEM_SAFE_FREE(points2d);
+}
+
+/* Simplify alternate vertex of stroke except extrems */
+void BKE_gpencil_simplify_fixed(bGPDstroke *gps)
+{
+ if (gps->totpoints < 5) {
+ return;
+ }
+
+ /* save points */
+ bGPDspoint *old_points = MEM_dupallocN(gps->points);
+ MDeformVert *old_dvert = NULL;
+ MDeformVert *dvert_src = NULL;
+
+ if (gps->dvert != NULL) {
+ old_dvert = MEM_dupallocN(gps->dvert);
+ }
+
+ /* resize gps */
+ int newtot = (gps->totpoints - 2) / 2;
+ if (((gps->totpoints - 2) % 2) > 0) {
+ newtot++;
+ }
+ newtot += 2;
+
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
+ }
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ gps->tot_triangles = 0;
+
+ int j = 0;
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt_src = &old_points[i];
+ bGPDspoint *pt = &gps->points[j];
+
+
+ if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) {
+ memcpy(pt, pt_src, sizeof(bGPDspoint));
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ MDeformVert *dvert = &gps->dvert[j];
+ memcpy(dvert, dvert_src, sizeof(MDeformVert));
+ if (dvert_src->dw) {
+ memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
+ }
+ }
+ j++;
+ }
+ else {
+ if (gps->dvert != NULL) {
+ dvert_src = &old_dvert[i];
+ BKE_gpencil_free_point_weights(dvert_src);
+ }
+ }
+ }
+
+ gps->totpoints = j;
+
+ MEM_SAFE_FREE(old_points);
+ MEM_SAFE_FREE(old_dvert);
+}
+
+/* *************************************************** */
+/* Modifier Utilities */
+
+/* Lattice Modifier ---------------------------------- */
+/* Usually, evaluation of the lattice modifier is self-contained.
+ * However, since GP's modifiers operate on a per-stroke basis,
+ * we need to these two extra functions that called before/after
+ * each loop over all the geometry being evaluated.
+ */
+
+ /* init lattice deform data */
+void BKE_gpencil_lattice_init(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ Object *latob = NULL;
+
+ latob = mmd->object;
+ if ((!latob) || (latob->type != OB_LATTICE)) {
+ return;
+ }
+ if (mmd->cache_data) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ }
+
+ /* init deform data */
+ mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob);
+ }
+ }
+}
+
+/* clear lattice deform data */
+void BKE_gpencil_lattice_clear(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (md->type == eGpencilModifierType_Lattice) {
+ LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
+ if ((mmd) && (mmd->cache_data)) {
+ end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
+ mmd->cache_data = NULL;
+ }
+ }
+ }
+}
+
+/* *************************************************** */
+/* Modifier Methods - Evaluation Loops, etc. */
+
+/* check if exist geometry modifiers */
+bool BKE_gpencil_has_geometry_modifiers(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti && mti->generateStrokes) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* check if exist time modifiers */
+bool BKE_gpencil_has_time_modifiers(Object *ob)
+{
+ GpencilModifierData *md;
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti && mti->remapTime) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* apply stroke modifiers */
+void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, bool is_render)
+{
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
+ continue;
+ }
+
+ if (mti && mti->deformStroke) {
+ mti->deformStroke(md, depsgraph, ob, gpl, gps);
+
+ /* some modifiers could require a recalc of fill triangulation data */
+ if (gpd->flag & GP_DATA_STROKE_FORCE_RECALC) {
+ if (ELEM(md->type,
+ eGpencilModifierType_Armature,
+ eGpencilModifierType_Hook,
+ eGpencilModifierType_Lattice,
+ eGpencilModifierType_Offset))
+ {
+
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* apply stroke geometry modifiers */
+void BKE_gpencil_geometry_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render)
+{
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
+ continue;
+ }
+
+ if (mti->generateStrokes) {
+ mti->generateStrokes(md, depsgraph, ob, gpl, gpf);
+ }
+ }
+ }
+}
+
+/* apply time modifiers */
+int BKE_gpencil_time_modifier(Depsgraph *depsgraph, Scene *scene, Object *ob,
+ bGPDlayer *gpl, int cfra, bool is_render)
+{
+ GpencilModifierData *md;
+ bGPdata *gpd = ob->data;
+ const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
+ int nfra = cfra;
+
+ for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
+ if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
+ continue;
+ }
+
+ if (mti->remapTime) {
+ nfra = mti->remapTime(md, depsgraph, scene, ob, gpl, cfra);
+ /* if the frame number changed, don't evaluate more and return */
+ if (nfra != cfra) {
+ return nfra;
+ }
+ }
+ }
+ }
+
+ /* if no time modifier, return original frame number */
+ return nfra;
+}
+/* *************************************************** */
+
+void BKE_gpencil_eval_geometry(Depsgraph *depsgraph,
+ bGPdata *gpd)
+{
+ DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
+ int ctime = (int)DEG_get_ctime(depsgraph);
+
+ /* update active frame */
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
+ }
+
+ /* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()?
+ * This would be better than inventing our own logic for this stuff...
+ */
+
+ /* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node)
+ * later when there's more happening here. For now, let's just keep this in here to avoid
+ * needing to have one more node slowing down evaluation...
+ */
+ if (DEG_is_active(depsgraph)) {
+ bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
+
+ /* sync "actframe" changes back to main-db too,
+ * so that editing tools work with copy-on-write
+ * when the current frame changes
+ */
+ for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) {
+ gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
+ }
+ }
+}
+
+void BKE_gpencil_modifier_init(void)
+{
+ /* Initialize modifier types */
+ gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */
+}
+
+GpencilModifierData *BKE_gpencil_modifier_new(int type)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+ GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
+
+ /* note, this name must be made unique later */
+ BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
+
+ md->type = type;
+ md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | eGpencilModifierMode_Expanded;
+ md->flag = eGpencilModifierFlag_StaticOverride_Local;
+
+ if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode)
+ md->mode |= eGpencilModifierMode_Editmode;
+
+ if (mti->initData) mti->initData(md);
+
+ return md;
+}
+
+static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
+}
+
+void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
+ }
+ }
+
+ if (mti->freeData) mti->freeData(md);
+ if (md->error) MEM_freeN(md->error);
+
+ MEM_freeN(md);
+}
+
+void BKE_gpencil_modifier_free(GpencilModifierData *md)
+{
+ BKE_gpencil_modifier_free_ex(md, 0);
+}
+
+/* check unique name */
+bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
+{
+ if (modifiers && gmd) {
+ const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
+ return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), '.', offsetof(GpencilModifierData, name), sizeof(gmd->name));
+ }
+ return false;
+}
+
+bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ return mti->dependsOnTime && mti->dependsOnTime(md);
+}
+
+const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type)
+{
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
+ return modifier_gpencil_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
+
+ /* md_dst may have already be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (mti->freeData) {
+ mti->freeData(md_dst);
+ }
+
+ const size_t data_size = sizeof(GpencilModifierData);
+ const char *md_src_data = ((const char *)md_src) + data_size;
+ char *md_dst_data = ((char *)md_dst) + data_size;
+ BLI_assert(data_size <= (size_t)mti->struct_size);
+ memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size);
+}
+
+static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
+}
+
+void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag)
+{
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ target->mode = md->mode;
+ target->flag = md->flag;
+
+ if (mti->copyData) {
+ mti->copyData(md, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ else if (mti->foreachObjectLink) {
+ mti->foreachObjectLink(target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL);
+ }
+ }
+}
+
+void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copyData_ex(md, target, 0);
+}
+
+GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next)
+ if (md->type == type)
+ break;
+
+ return md;
+}
+
+void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->foreachIDLink) {
+ mti->foreachIDLink(md, ob, walk, userData);
+ }
+ else if (mti->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk;
+ mti->foreachObjectLink(md, ob, fp, userData);
+ }
+ }
+}
+
+void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData)
+{
+ GpencilModifierData *md = ob->greasepencil_modifiers.first;
+
+ for (; md; md = md->next) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+
+ if (mti->foreachTexLink)
+ mti->foreachTexLink(md, ob, walk, userData);
+ }
+}
+
+GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name)
+{
+ return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
+}
+
+void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag)
+{
+ bGPDspoint *temp_points;
+ MDeformVert *temp_dverts = NULL;
+ MDeformVert *dvert = NULL;
+ MDeformVert *dvert_final = NULL;
+ MDeformVert *dvert_next = NULL;
+ int totnewpoints, oldtotpoints;
+ int i2;
+
+ for (int s = 0; s < level; s++) {
+ totnewpoints = gps->totpoints - 1;
+ /* duplicate points in a temp area */
+ temp_points = MEM_dupallocN(gps->points);
+ oldtotpoints = gps->totpoints;
+
+ /* resize the points arrays */
+ gps->totpoints += totnewpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ temp_dverts = MEM_dupallocN(gps->dvert);
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
+ gps->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* move points from last to first to new place */
+ i2 = gps->totpoints - 1;
+ for (int i = oldtotpoints - 1; i > 0; i--) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ copy_v3_v3(&pt_final->x, &pt->x);
+ pt_final->pressure = pt->pressure;
+ pt_final->strength = pt->strength;
+ pt_final->time = pt->time;
+ pt_final->flag = pt->flag;
+
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_final = &gps->dvert[i2];
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = dvert->dw;
+ }
+ i2 -= 2;
+ }
+ /* interpolate mid points */
+ i2 = 1;
+ for (int i = 0; i < oldtotpoints - 1; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i2];
+
+ /* add a half way point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
+ pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
+ CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ pt_final->time = interpf(pt->time, next->time, 0.5f);
+
+ if (gps->dvert != NULL) {
+ dvert = &temp_dverts[i];
+ dvert_next = &temp_dverts[i + 1];
+ dvert_final = &gps->dvert[i2];
+
+ dvert_final->totweight = dvert->totweight;
+ dvert_final->dw = MEM_dupallocN(dvert->dw);
+
+ /* interpolate weight values */
+ for (int d = 0; d < dvert->totweight; d++) {
+ MDeformWeight *dw_a = &dvert->dw[d];
+ if (dvert_next->totweight > d) {
+ MDeformWeight *dw_b = &dvert_next->dw[d];
+ MDeformWeight *dw_final = &dvert_final->dw[d];
+ dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
+ }
+ }
+ }
+
+ i2 += 2;
+ }
+
+ MEM_SAFE_FREE(temp_points);
+ MEM_SAFE_FREE(temp_dverts);
+
+ /* move points to smooth stroke (not simple flag )*/
+ if ((flag & GP_SUBDIV_SIMPLE) == 0) {
+ /* duplicate points in a temp area with the new subdivide data */
+ temp_points = MEM_dupallocN(gps->points);
+
+ /* extreme points are not changed */
+ for (int i = 0; i < gps->totpoints - 2; i++) {
+ bGPDspoint *pt = &temp_points[i];
+ bGPDspoint *next = &temp_points[i + 1];
+ bGPDspoint *pt_final = &gps->points[i + 1];
+
+ /* move point */
+ interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
+ }
+ /* free temp memory */
+ MEM_SAFE_FREE(temp_points);
+ }
+
+ }
+}
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
deleted file mode 100644
index 62f608f8565..00000000000
--- a/source/blender/blenkernel/intern/group.c
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/group.c
- * \ingroup bke
- */
-
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_group_types.h"
-#include "DNA_material_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_particle_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-
-
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-#include "BKE_group.h"
-#include "BKE_icons.h"
-#include "BKE_library.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-#include "BKE_scene.h" /* BKE_scene_base_find */
-
-static void free_group_object(GroupObject *go)
-{
- MEM_freeN(go);
-}
-
-/** Free (or release) any data used by this group (does not free the group itself). */
-void BKE_group_free(Group *group)
-{
- /* don't free group itself */
- GroupObject *go;
-
- /* No animdata here. */
-
- while ((go = BLI_pophead(&group->gobject))) {
- free_group_object(go);
- }
-
- BKE_previewimg_free(&group->preview);
-}
-
-Group *BKE_group_add(Main *bmain, const char *name)
-{
- Group *group;
-
- group = BKE_libblock_alloc(bmain, ID_GR, name, 0);
- id_us_min(&group->id);
- id_us_ensure_real(&group->id);
- group->layer = (1 << 20) - 1;
-
- group->preview = NULL;
-
- return group;
-}
-
-/**
- * Only copy internal data of Group ID from source to already allocated/initialized destination.
- * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
- *
- * WARNING! This function will not handle ID user count!
- *
- * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
- */
-void BKE_group_copy_data(Main *UNUSED(bmain), Group *group_dst, const Group *group_src, const int flag)
-{
- BLI_duplicatelist(&group_dst->gobject, &group_src->gobject);
-
- /* Do not copy group's preview (same behavior as for objects). */
- if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
- BKE_previewimg_id_copy(&group_dst->id, &group_src->id);
- }
- else {
- group_dst->preview = NULL;
- }
-}
-
-Group *BKE_group_copy(Main *bmain, const Group *group)
-{
- Group *group_copy;
- BKE_id_copy_ex(bmain, &group->id, (ID **)&group_copy, 0, false);
- return group_copy;
-}
-
-void BKE_group_make_local(Main *bmain, Group *group, const bool lib_local)
-{
- BKE_id_make_local_generic(bmain, &group->id, true, lib_local);
-}
-
-/* external */
-static bool group_object_add_internal(Group *group, Object *ob)
-{
- GroupObject *go;
-
- if (group == NULL || ob == NULL) {
- return false;
- }
-
- /* check if the object has been added already */
- if (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob))) {
- return false;
- }
-
- go = MEM_callocN(sizeof(GroupObject), "groupobject");
- BLI_addtail(&group->gobject, go);
-
- go->ob = ob;
- id_us_ensure_real(&go->ob->id);
-
- return true;
-}
-
-bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base)
-{
- if (group_object_add_internal(group, object)) {
- if ((object->flag & OB_FROMGROUP) == 0) {
-
- if (scene && base == NULL)
- base = BKE_scene_base_find(scene, object);
-
- object->flag |= OB_FROMGROUP;
-
- if (base)
- base->flag |= OB_FROMGROUP;
- }
- return true;
- }
- else {
- return false;
- }
-}
-
-/* also used for (ob == NULL) */
-static int group_object_unlink_internal(Group *group, Object *ob)
-{
- GroupObject *go, *gon;
- int removed = 0;
- if (group == NULL) return 0;
-
- go = group->gobject.first;
- while (go) {
- gon = go->next;
- if (go->ob == ob) {
- BLI_remlink(&group->gobject, go);
- free_group_object(go);
- removed = 1;
- /* should break here since an object being in a group twice cant happen? */
- }
- go = gon;
- }
- return removed;
-}
-
-static bool group_object_cyclic_check_internal(Object *object, Group *group)
-{
- if (object->dup_group) {
- Group *dup_group = object->dup_group;
- if ((dup_group->id.tag & LIB_TAG_DOIT) == 0) {
- /* Cycle already exists in groups, let's prevent further crappyness */
- return true;
- }
- /* flag the object to identify cyclic dependencies in further dupli groups */
- dup_group->id.tag &= ~LIB_TAG_DOIT;
-
- if (dup_group == group)
- return true;
- else {
- GroupObject *gob;
- for (gob = dup_group->gobject.first; gob; gob = gob->next) {
- if (group_object_cyclic_check_internal(gob->ob, group)) {
- return true;
- }
- }
- }
-
- /* un-flag the object, it's allowed to have the same group multiple times in parallel */
- dup_group->id.tag |= LIB_TAG_DOIT;
- }
-
- return false;
-}
-
-bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group)
-{
- /* first flag all groups */
- BKE_main_id_tag_listbase(&bmain->group, LIB_TAG_DOIT, true);
-
- return group_object_cyclic_check_internal(object, group);
-}
-
-bool BKE_group_object_unlink(Main *bmain, Group *group, Object *object, Scene *scene, Base *base)
-{
- if (group_object_unlink_internal(group, object)) {
- /* object can be NULL */
- if (object && BKE_group_object_find(bmain, NULL, object) == NULL) {
- if (scene && base == NULL)
- base = BKE_scene_base_find(scene, object);
-
- object->flag &= ~OB_FROMGROUP;
-
- if (base)
- base->flag &= ~OB_FROMGROUP;
- }
- return true;
- }
- else {
- return false;
- }
-}
-
-bool BKE_group_object_exists(Group *group, Object *ob)
-{
- if (group == NULL || ob == NULL) {
- return false;
- }
- else {
- return (BLI_findptr(&group->gobject, ob, offsetof(GroupObject, ob)) != NULL);
- }
-}
-
-Group *BKE_group_object_find(Main *bmain, Group *group, Object *ob)
-{
- if (group)
- group = group->id.next;
- else
- group = bmain->group.first;
-
- while (group) {
- if (BKE_group_object_exists(group, ob))
- return group;
- group = group->id.next;
- }
- return NULL;
-}
-
-bool BKE_group_is_animated(Group *group, Object *UNUSED(parent))
-{
- GroupObject *go;
-
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
- if (parent->nlastrips.first)
- return 1;
-#endif
-
- for (go = group->gobject.first; go; go = go->next)
- if (go->ob && go->ob->proxy)
- return true;
-
- return false;
-}
-
-#if 0 // add back when timeoffset & animsys work again
-/* only replaces object strips or action when parent nla instructs it */
-/* keep checking nla.c though, in case internal structure of strip changes */
-static void group_replaces_nla(Object *parent, Object *target, char mode)
-{
- static ListBase nlastrips = {NULL, NULL};
- static bAction *action = NULL;
- static bool done = false;
- bActionStrip *strip, *nstrip;
-
- if (mode == 's') {
-
- for (strip = parent->nlastrips.first; strip; strip = strip->next) {
- if (strip->object == target) {
- if (done == 0) {
- /* clear nla & action from object */
- nlastrips = target->nlastrips;
- BLI_listbase_clear(&target->nlastrips);
- action = target->action;
- target->action = NULL;
- target->nlaflag |= OB_NLA_OVERRIDE;
- done = true;
- }
- nstrip = MEM_dupallocN(strip);
- BLI_addtail(&target->nlastrips, nstrip);
- }
- }
- }
- else if (mode == 'e') {
- if (done) {
- BLI_freelistN(&target->nlastrips);
- target->nlastrips = nlastrips;
- target->action = action;
-
- BLI_listbase_clear(&nlastrips); /* not needed, but yah... :) */
- action = NULL;
- done = false;
- }
- }
-}
-#endif
-
-/* puts all group members in local timing system, after this call
- * you can draw everything, leaves tags in objects to signal it needs further updating */
-
-/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
-void BKE_group_handle_recalc_and_update(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *UNUSED(parent), Group *group)
-{
- GroupObject *go;
-
-#if 0 /* warning, isn't clearing the recalc flag on the object which causes it to run all the time,
- * not just on frame change.
- * This isn't working because the animation data is only re-evaluated on frame change so commenting for now
- * but when its enabled at some point it will need to be changed so as not to update so much - campbell */
-
- /* if animated group... */
- if (parent->nlastrips.first) {
- int cfrao;
-
- /* switch to local time */
- cfrao = scene->r.cfra;
-
- /* we need a DAG per group... */
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob && go->recalc) {
- go->ob->recalc = go->recalc;
-
- group_replaces_nla(parent, go->ob, 's');
- BKE_object_handle_update(eval_ctx, scene, go->ob);
- group_replaces_nla(parent, go->ob, 'e');
-
- /* leave recalc tags in case group members are in normal scene */
- go->ob->recalc = go->recalc;
- }
- }
-
- /* restore */
- scene->r.cfra = cfrao;
- }
- else
-#endif
- {
- /* only do existing tags, as set by regular depsgraph */
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob) {
- if (go->ob->recalc) {
- BKE_object_handle_update(bmain, eval_ctx, scene, go->ob);
- }
- }
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index e49f24c8120..2a348751365 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -37,23 +37,27 @@
#include "MEM_guardedalloc.h"
-#include "DNA_group_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
-#include "DNA_brush_types.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_linklist_lockfree.h"
#include "BLI_string.h"
+#include "BLI_fileops.h"
#include "BLI_threads.h"
#include "BKE_icons.h"
#include "BKE_global.h" /* only for G.background test */
+#include "BKE_studiolight.h"
#include "BLI_sys_types.h" // for intptr_t support
@@ -63,6 +67,14 @@
#include "IMB_imbuf_types.h"
#include "IMB_thumbs.h"
+/**
+ * Only allow non-managed icons to be removed (by Python for eg).
+ * Previews & ID's have their own functions to remove icons.
+ */
+enum {
+ ICON_FLAG_MANAGED = (1 << 0),
+};
+
/* GLOBALS */
static GHash *gIcons = NULL;
@@ -85,6 +97,19 @@ static void icon_free(void *val)
Icon *icon = val;
if (icon) {
+ if (icon->obj_type == ICON_DATA_GEOM) {
+ struct Icon_Geom *obj = icon->obj;
+ if (obj->mem) {
+ /* coords & colors are part of this memory. */
+ MEM_freeN((void *)obj->mem);
+ }
+ else {
+ MEM_freeN((void *)obj->coords);
+ MEM_freeN((void *)obj->colors);
+ }
+ MEM_freeN(icon->obj);
+ }
+
if (icon->drawinfo_free) {
icon->drawinfo_free(icon->drawinfo);
}
@@ -95,6 +120,31 @@ static void icon_free(void *val)
}
}
+static void icon_free_data(int icon_id, Icon *icon)
+{
+ if (icon->obj_type == ICON_DATA_ID) {
+ ((ID *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_PREVIEW) {
+ ((PreviewImage *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_GPLAYER) {
+ ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_GEOM) {
+ ((struct Icon_Geom *)(icon->obj))->icon_id = 0;
+ }
+ else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
+ StudioLight *sl = icon->obj;
+ if (sl != NULL) {
+ BKE_studiolight_unset_icon_id(sl, icon_id);
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+}
+
/* create an id for a new icon and make sure that ids from deleted icons get reused
* after the integer number range is used up */
static int get_next_free_id(void)
@@ -282,8 +332,9 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id)
ID_PRV_CASE(ID_IM, Image);
ID_PRV_CASE(ID_BR, Brush);
ID_PRV_CASE(ID_OB, Object);
- ID_PRV_CASE(ID_GR, Group);
+ ID_PRV_CASE(ID_GR, Collection);
ID_PRV_CASE(ID_SCE, Scene);
+ ID_PRV_CASE(ID_SCR, bScreen);
#undef ID_PRV_CASE
default:
break;
@@ -476,6 +527,7 @@ void BKE_icon_changed(const int icon_id)
if (icon) {
/* We *only* expect ID-tied icons here, not non-ID icon/preview! */
BLI_assert(icon->id_type != 0);
+ BLI_assert(icon->obj_type == ICON_DATA_ID);
/* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here ,
* we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */
@@ -492,22 +544,31 @@ void BKE_icon_changed(const int icon_id)
}
}
-static int icon_id_ensure_create_icon(struct ID *id)
+static Icon *icon_create(int icon_id, int obj_type, void *obj)
{
- BLI_assert(BLI_thread_is_main());
+ Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__);
- Icon *new_icon = NULL;
-
- new_icon = MEM_mallocN(sizeof(Icon), __func__);
-
- new_icon->obj = id;
- new_icon->id_type = GS(id->name);
+ new_icon->obj_type = obj_type;
+ new_icon->obj = obj;
+ new_icon->id_type = 0;
+ new_icon->flag = 0;
/* next two lines make sure image gets created */
new_icon->drawinfo = NULL;
new_icon->drawinfo_free = NULL;
- BLI_ghash_insert(gIcons, POINTER_FROM_INT(id->icon_id), new_icon);
+ BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), new_icon);
+
+ return new_icon;
+}
+
+static int icon_id_ensure_create_icon(struct ID *id)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ Icon *icon = icon_create(id->icon_id, ICON_DATA_ID, id);
+ icon->id_type = GS(id->name);
+ icon->flag = ICON_FLAG_MANAGED;
return id->icon_id;
}
@@ -541,13 +602,49 @@ int BKE_icon_id_ensure(struct ID *id)
return icon_id_ensure_create_icon(id);
}
+
+static int icon_gplayer_color_ensure_create_icon(bGPDlayer *gpl)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ /* NOTE: The color previews for GP Layers don't really need
+ * to be "rendered" to image per se (as it will just be a plain
+ * colored rectangle), we need to define icon data here so that
+ * we can store a pointer to the layer data in icon->obj.
+ */
+ Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl);
+ icon->flag = ICON_FLAG_MANAGED;
+
+ return gpl->runtime.icon_id;
+}
+
+int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
+{
+ /* Never handle icons in non-main thread! */
+ BLI_assert(BLI_thread_is_main());
+
+ if (!gpl || G.background) {
+ return 0;
+ }
+
+ if (gpl->runtime.icon_id)
+ return gpl->runtime.icon_id;
+
+ gpl->runtime.icon_id = get_next_free_id();
+
+ if (!gpl->runtime.icon_id) {
+ printf("%s: Internal error - not enough IDs\n", __func__);
+ return 0;
+ }
+
+ return icon_gplayer_color_ensure_create_icon(gpl);
+}
+
/**
* Return icon id of given preview, or create new icon if not found.
*/
int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
{
- Icon *new_icon = NULL;
-
if (!preview || G.background)
return 0;
@@ -578,16 +675,8 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
return icon_id_ensure_create_icon(id);
}
- new_icon = MEM_mallocN(sizeof(Icon), __func__);
-
- new_icon->obj = preview;
- new_icon->id_type = 0; /* Special, tags as non-ID icon/preview. */
-
- /* next two lines make sure image gets created */
- new_icon->drawinfo = NULL;
- new_icon->drawinfo_free = NULL;
-
- BLI_ghash_insert(gIcons, POINTER_FROM_INT(preview->icon_id), new_icon);
+ Icon *icon = icon_create(preview->icon_id, ICON_DATA_PREVIEW, preview);
+ icon->flag = ICON_FLAG_MANAGED;
return preview->icon_id;
}
@@ -649,21 +738,127 @@ void BKE_icon_id_delete(struct ID *id)
/**
* Remove icon and free data.
*/
-void BKE_icon_delete(const int icon_id)
+bool BKE_icon_delete(const int icon_id)
{
- Icon *icon;
+ if (icon_id == 0) {
+ /* no icon defined for library object */
+ return false;
+ }
- if (!icon_id) return; /* no icon defined for library object */
+ Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
+ if (icon) {
+ icon_free_data(icon_id, icon);
+ icon_free(icon);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
- icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
+bool BKE_icon_delete_unmanaged(const int icon_id)
+{
+ if (icon_id == 0) {
+ /* no icon defined for library object */
+ return false;
+ }
+ Icon *icon = BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL);
if (icon) {
- if (icon->id_type != 0) {
- ((ID *)(icon->obj))->icon_id = 0;
+ if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) {
+ BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon);
+ return false;
}
else {
- ((PreviewImage *)(icon->obj))->icon_id = 0;
+ icon_free_data(icon_id, icon);
+ icon_free(icon);
+ return true;
}
- icon_free(icon);
}
+ else {
+ return false;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Geometry Icon
+ * \{ */
+
+int BKE_icon_geom_ensure(struct Icon_Geom *geom)
+{
+ BLI_assert(BLI_thread_is_main());
+
+ if (geom->icon_id) {
+ return geom->icon_id;
+ }
+
+ geom->icon_id = get_next_free_id();
+
+ icon_create(geom->icon_id, ICON_DATA_GEOM, geom);
+ /* Not managed for now, we may want this to be configurable per icon). */
+
+ return geom->icon_id;
+}
+
+struct Icon_Geom *BKE_icon_geom_from_memory(const uchar *data, size_t data_len)
+{
+ BLI_assert(BLI_thread_is_main());
+ if (data_len <= 8) {
+ goto fail;
+ }
+ /* Skip the header. */
+ data_len -= 8;
+ const int div = 3 * 2 * 3;
+ const int coords_len = data_len / div;
+ if (coords_len * div != data_len) {
+ goto fail;
+ }
+
+ const uchar header[4] = {'V', 'C', 'O', 0};
+ const uchar *p = data;
+ if (memcmp(p, header, ARRAY_SIZE(header)) != 0) {
+ goto fail;
+ }
+ p += 4;
+
+ struct Icon_Geom *geom = MEM_mallocN(sizeof(*geom), __func__);
+ geom->coords_range[0] = (int)*p++;
+ geom->coords_range[1] = (int)*p++;
+ /* x, y ignored for now */
+ p += 2;
+
+ geom->coords_len = coords_len;
+ geom->coords = (const void *)p;
+ geom->colors = (const void *)(p + (data_len / 3));
+ geom->icon_id = 0;
+ geom->mem = data;
+ return geom;
+
+fail:
+ MEM_freeN((void *)data);
+ return NULL;
+}
+
+struct Icon_Geom *BKE_icon_geom_from_file(const char *filename)
+{
+ BLI_assert(BLI_thread_is_main());
+ size_t data_len;
+ uchar *data = BLI_file_read_binary_as_mem(filename, 0, &data_len);
+ if (data == NULL) {
+ return NULL;
+ }
+ return BKE_icon_geom_from_memory(data, data_len);
+}
+
+/** \} */
+
+/** \name Studio Light Icon
+ * \{ */
+int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
+{
+ int icon_id = get_next_free_id();
+ Icon *icon = icon_create(icon_id, ICON_DATA_STUDIOLIGHT, sl);
+ icon->id_type = id_type;
+ return icon_id;
}
+/** \} */
diff --git a/source/blender/blenkernel/intern/icons_rasterize.c b/source/blender/blenkernel/intern/icons_rasterize.c
new file mode 100644
index 00000000000..24576c24953
--- /dev/null
+++ b/source/blender/blenkernel/intern/icons_rasterize.c
@@ -0,0 +1,146 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenkernel/intern/icons_rasterize.c
+ * \ingroup bke
+ */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_bitmap_draw_2d.h"
+#include "BLI_math_geom.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_icons.h"
+
+#include "BLI_strict_flags.h"
+
+struct UserRasterInfo {
+ int pt[3][2];
+ const uint *color;
+ /* only for smooth shading */
+ struct {
+ float pt_fl[3][2];
+ uint color_u[3][4];
+ } smooth;
+ int rect_size[2];
+ uint *rect;
+};
+
+static void tri_fill_flat(int x, int x_end, int y, void *user_data)
+{
+ struct UserRasterInfo *data = user_data;
+ uint *p = &data->rect[(y * data->rect_size[1]) + x];
+ uint col = data->color[0];
+ while (x++ != x_end) {
+ *p++ = col;
+ }
+}
+
+static void tri_fill_smooth(int x, int x_end, int y, void *user_data)
+{
+ struct UserRasterInfo *data = user_data;
+ uint *p = &data->rect[(y * data->rect_size[1]) + x];
+ float pt_step_fl[2] = {(float)x, (float)y};
+ while (x++ != x_end) {
+ float w[3];
+ barycentric_weights_v2_clamped(UNPACK3(data->smooth.pt_fl), pt_step_fl, w);
+
+ uint col_u[4] = {0, 0, 0, 0};
+ for (uint corner = 0; corner < 3; corner++) {
+ for (uint chan = 0; chan < 4; chan++) {
+ col_u[chan] += data->smooth.color_u[corner][chan] * (uint)(w[corner] * 255.0f);
+ }
+ }
+ union {
+ uint as_u32;
+ uchar as_bytes[4];
+ } col;
+ col.as_bytes[0] = (uchar)(col_u[0] / 255);
+ col.as_bytes[1] = (uchar)(col_u[1] / 255);
+ col.as_bytes[2] = (uchar)(col_u[2] / 255);
+ col.as_bytes[3] = (uchar)(col_u[3] / 255);
+ *p++ = col.as_u32;
+
+ pt_step_fl[0] += 1.0f;
+ }
+}
+
+ImBuf *BKE_icon_geom_rasterize(
+ const struct Icon_Geom *geom,
+ const unsigned int size_x, const unsigned int size_y)
+{
+ const int coords_len = geom->coords_len;
+
+ const uchar (*pos)[2] = geom->coords;
+ const uint *col = (void *)geom->colors;
+
+ /* TODO(campbell): Currently rasterizes to fixed size, then scales.
+ * Should rasterize to double size for eg instead. */
+ const int rect_size[2] = {max_ii(256, (int)size_x * 2), max_ii(256, (int)size_y * 2)};
+
+ ImBuf *ibuf = IMB_allocImBuf((uint)rect_size[0], (uint)rect_size[1], 32, IB_rect);
+
+ struct UserRasterInfo data;
+
+ data.rect_size[0] = rect_size[0];
+ data.rect_size[1] = rect_size[1];
+
+ data.rect = ibuf->rect;
+
+ float scale[2];
+ const bool use_scale = (rect_size[0] != 256) || (rect_size[1] != 256);
+
+ if (use_scale) {
+ scale[0] = ((float)rect_size[0] / 256.0f);
+ scale[1] = ((float)rect_size[1] / 256.0f);
+ }
+
+ for (int t = 0; t < coords_len; t += 1, pos += 3, col += 3) {
+ if (use_scale) {
+ ARRAY_SET_ITEMS(data.pt[0], (int)(pos[0][0] * scale[0]), (int)(pos[0][1] * scale[1]));
+ ARRAY_SET_ITEMS(data.pt[1], (int)(pos[1][0] * scale[0]), (int)(pos[1][1] * scale[1]));
+ ARRAY_SET_ITEMS(data.pt[2], (int)(pos[2][0] * scale[0]), (int)(pos[2][1] * scale[1]));
+ }
+ else {
+ ARRAY_SET_ITEMS(data.pt[0], UNPACK2(pos[0]));
+ ARRAY_SET_ITEMS(data.pt[1], UNPACK2(pos[1]));
+ ARRAY_SET_ITEMS(data.pt[2], UNPACK2(pos[2]));
+ }
+ data.color = col;
+ if ((col[0] == col[1]) && (col[0] == col[2])) {
+ BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_flat, &data);
+ }
+ else {
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[0], UNPACK2_EX((float), data.pt[0], ));
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[1], UNPACK2_EX((float), data.pt[1], ));
+ ARRAY_SET_ITEMS(data.smooth.pt_fl[2], UNPACK2_EX((float), data.pt[2], ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[0], UNPACK4_EX((uint), ((uchar *)(col + 0)), ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[1], UNPACK4_EX((uint), ((uchar *)(col + 1)), ));
+ ARRAY_SET_ITEMS(data.smooth.color_u[2], UNPACK4_EX((uint), ((uchar *)(col + 2)), ));
+ BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_smooth, &data);
+ }
+ }
+ IMB_scaleImBuf(ibuf, size_x, size_y);
+ return ibuf;
+}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index d995dce1259..d97c00f8229 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -39,7 +39,7 @@
#include "BLT_translation.h"
-#include "BKE_library.h"
+#include "BKE_main.h"
#include "BKE_idcode.h"
typedef struct {
@@ -56,44 +56,46 @@ typedef struct {
/* WARNING! Keep it in sync with i18n contexts in BLT_translation.h */
static IDType idtypes[] = {
/** ID's directly below must all be in #Main, and be kept in sync with #MAX_LIBARRAY (membership, not order) */
- { ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE },
- { ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE },
- { ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE },
- { ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE }, /* rename gpencil */
- { ID_GR, "Group", "groups", BLT_I18NCONTEXT_ID_GROUP, IDTYPE_FLAGS_ISLINKABLE },
- { ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE }, /* deprecated */
- { ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 },
- { ID_LA, "Lamp", "lamps", BLT_I18NCONTEXT_ID_LAMP, IDTYPE_FLAGS_ISLINKABLE },
- { ID_LI, "Library", "libraries", BLT_I18NCONTEXT_ID_LIBRARY, 0 },
- { ID_LS, "FreestyleLineStyle", "linestyles", BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_LT, "Lattice", "lattices", BLT_I18NCONTEXT_ID_LATTICE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_MA, "Material", "materials", BLT_I18NCONTEXT_ID_MATERIAL, IDTYPE_FLAGS_ISLINKABLE },
- { ID_MB, "Metaball", "metaballs", BLT_I18NCONTEXT_ID_METABALL, IDTYPE_FLAGS_ISLINKABLE },
- { ID_MC, "MovieClip", "movieclips", BLT_I18NCONTEXT_ID_MOVIECLIP, IDTYPE_FLAGS_ISLINKABLE },
- { ID_ME, "Mesh", "meshes", BLT_I18NCONTEXT_ID_MESH, IDTYPE_FLAGS_ISLINKABLE },
- { ID_MSK, "Mask", "masks", BLT_I18NCONTEXT_ID_MASK, IDTYPE_FLAGS_ISLINKABLE },
- { ID_NT, "NodeTree", "node_groups", BLT_I18NCONTEXT_ID_NODETREE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_OB, "Object", "objects", BLT_I18NCONTEXT_ID_OBJECT, IDTYPE_FLAGS_ISLINKABLE },
- { ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE },
- { ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, 0 },
- { ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */
- { ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE },
- { ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE },
- { ID_TE, "Texture", "textures", BLT_I18NCONTEXT_ID_TEXTURE, IDTYPE_FLAGS_ISLINKABLE },
- { ID_TXT, "Text", "texts", BLT_I18NCONTEXT_ID_TEXT, IDTYPE_FLAGS_ISLINKABLE },
- { ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE },
- { ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE },
- { ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+ {ID_AC, "Action", "actions", BLT_I18NCONTEXT_ID_ACTION, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_AR, "Armature", "armatures", BLT_I18NCONTEXT_ID_ARMATURE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_BR, "Brush", "brushes", BLT_I18NCONTEXT_ID_BRUSH, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_CA, "Camera", "cameras", BLT_I18NCONTEXT_ID_CAMERA, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_CF, "CacheFile", "cache_files", BLT_I18NCONTEXT_ID_CACHEFILE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_GR, "Collection", "collections", BLT_I18NCONTEXT_ID_COLLECTION, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_CU, "Curve", "curves", BLT_I18NCONTEXT_ID_CURVE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_GD, "GPencil", "grease_pencil", BLT_I18NCONTEXT_ID_GPENCIL, IDTYPE_FLAGS_ISLINKABLE}, /* rename gpencil */
+ {ID_IM, "Image", "images", BLT_I18NCONTEXT_ID_IMAGE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_IP, "Ipo", "ipos", "", IDTYPE_FLAGS_ISLINKABLE}, /* deprecated */
+ {ID_KE, "Key", "shape_keys", BLT_I18NCONTEXT_ID_SHAPEKEY, 0 },
+ {ID_LA, "Light", "lights", BLT_I18NCONTEXT_ID_LAMP, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_LI, "Library", "libraries", BLT_I18NCONTEXT_ID_LIBRARY, 0 },
+ {ID_LS, "FreestyleLineStyle", "linestyles", BLT_I18NCONTEXT_ID_FREESTYLELINESTYLE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_LT, "Lattice", "lattices", BLT_I18NCONTEXT_ID_LATTICE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MA, "Material", "materials", BLT_I18NCONTEXT_ID_MATERIAL, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MB, "Metaball", "metaballs", BLT_I18NCONTEXT_ID_METABALL, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MC, "MovieClip", "movieclips", BLT_I18NCONTEXT_ID_MOVIECLIP, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_ME, "Mesh", "meshes", BLT_I18NCONTEXT_ID_MESH, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_MSK, "Mask", "masks", BLT_I18NCONTEXT_ID_MASK, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_NT, "NodeTree", "node_groups", BLT_I18NCONTEXT_ID_NODETREE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_OB, "Object", "objects", BLT_I18NCONTEXT_ID_OBJECT, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_PA, "ParticleSettings", "particles", BLT_I18NCONTEXT_ID_PARTICLESETTINGS, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_PAL, "Palettes", "palettes", BLT_I18NCONTEXT_ID_PALETTE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_PC, "PaintCurve", "paint_curves", BLT_I18NCONTEXT_ID_PAINTCURVE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_LP, "LightProbe", "light_probes", BLT_I18NCONTEXT_ID_LIGHTPROBE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SCE, "Scene", "scenes", BLT_I18NCONTEXT_ID_SCENE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SCR, "Screen", "screens", BLT_I18NCONTEXT_ID_SCREEN, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SEQ, "Sequence", "sequences", BLT_I18NCONTEXT_ID_SEQUENCE, 0 }, /* not actually ID data */
+ {ID_SPK, "Speaker", "speakers", BLT_I18NCONTEXT_ID_SPEAKER, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_SO, "Sound", "sounds", BLT_I18NCONTEXT_ID_SOUND, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_TE, "Texture", "textures", BLT_I18NCONTEXT_ID_TEXTURE, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_TXT, "Text", "texts", BLT_I18NCONTEXT_ID_TEXT, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_VF, "VFont", "fonts", BLT_I18NCONTEXT_ID_VFONT, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_WO, "World", "worlds", BLT_I18NCONTEXT_ID_WORLD, IDTYPE_FLAGS_ISLINKABLE},
+ {ID_WM, "WindowManager", "window_managers", BLT_I18NCONTEXT_ID_WINDOWMANAGER, 0 },
+ {ID_WS, "WorkSpace", "workspaces", BLT_I18NCONTEXT_ID_WORKSPACE, IDTYPE_FLAGS_ISLINKABLE},
/** Keep last, not an ID exactly, only include for completeness */
- { ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
+ {ID_ID, "ID", "ids", BLT_I18NCONTEXT_ID_ID, 0 }, /* plural is fake */
};
/* -1 for ID_ID */
@@ -203,6 +205,7 @@ int BKE_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(PA);
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
+ CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
@@ -210,6 +213,7 @@ int BKE_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(TXT);
CASE_IDFILTER(VF);
CASE_IDFILTER(WO);
+ CASE_IDFILTER(WS);
default:
return 0;
}
@@ -247,6 +251,7 @@ short BKE_idcode_from_idfilter(const int idfilter)
CASE_IDFILTER(PA);
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
+ CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
@@ -294,6 +299,7 @@ int BKE_idcode_to_index(const short idcode)
CASE_IDINDEX(PA);
CASE_IDINDEX(PAL);
CASE_IDINDEX(PC);
+ CASE_IDINDEX(LP);
CASE_IDINDEX(SCE);
CASE_IDINDEX(SCR);
CASE_IDINDEX(SPK);
@@ -303,6 +309,7 @@ int BKE_idcode_to_index(const short idcode)
CASE_IDINDEX(VF);
CASE_IDINDEX(WM);
CASE_IDINDEX(WO);
+ CASE_IDINDEX(WS);
}
BLI_assert(0);
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 7a526d31567..8cc40d4e74c 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -476,6 +476,7 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag)
BLI_assert(prop->type == IDP_GROUP);
newp = idp_generic_copy(prop, flag);
newp->len = prop->len;
+ newp->subtype = prop->subtype;
for (link = prop->data.group.first; link; link = link->next) {
BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag));
@@ -601,8 +602,9 @@ void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
/**
* If a property is missing in \a dest, add it.
+ * Do it recursively.
*/
-void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
+void IDP_MergeGroup_ex(IDProperty *dest, const IDProperty *src, const bool do_overwrite, const int flag)
{
IDProperty *prop;
@@ -611,14 +613,30 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw
if (do_overwrite) {
for (prop = src->data.group.first; prop; prop = prop->next) {
- IDProperty *copy = IDP_CopyProperty(prop);
+ if (prop->type == IDP_GROUP) {
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+
+ if (prop_exist != NULL) {
+ IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
+ continue;
+ }
+ }
+
+ IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
IDP_ReplaceInGroup(dest, copy);
}
}
else {
for (prop = src->data.group.first; prop; prop = prop->next) {
- if (IDP_GetPropertyFromGroup(dest, prop->name) == NULL) {
- IDProperty *copy = IDP_CopyProperty(prop);
+ IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name);
+ if (prop_exist != NULL) {
+ if (prop->type == IDP_GROUP) {
+ IDP_MergeGroup_ex(prop_exist, prop, do_overwrite, flag);
+ continue;
+ }
+ }
+ else {
+ IDProperty *copy = IDP_CopyProperty_ex(prop, flag);
dest->len++;
BLI_addtail(&dest->data.group, copy);
}
@@ -627,6 +645,15 @@ void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overw
}
/**
+ * If a property is missing in \a dest, add it.
+ * Do it recursively.
+ */
+void IDP_MergeGroup(IDProperty *dest, const IDProperty *src, const bool do_overwrite)
+{
+ IDP_MergeGroup_ex(dest, src, do_overwrite, 0);
+}
+
+/**
* This function has a sanity check to make sure ID properties with the same name don't
* get added to the group.
*
@@ -1067,4 +1094,15 @@ void IDP_ClearProperty(IDProperty *prop)
prop->len = prop->totallen = 0;
}
+void IDP_Reset(IDProperty *prop, const IDProperty *reference)
+{
+ if (prop == NULL) {
+ return;
+ }
+ IDP_ClearProperty(prop);
+ if (reference != NULL) {
+ IDP_MergeGroup(prop, reference, true);
+ }
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 1d209dec935..f1a921650f0 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -68,7 +68,6 @@
#include "BLI_timecode.h" /* for stamp timecode format */
#include "BLI_utildefines.h"
-#include "BKE_bmfont.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -82,6 +81,7 @@
#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_sequencer.h" /* seq_foreground_frame_get() */
+#include "BKE_workspace.h"
#include "BLF_api.h"
@@ -185,76 +185,6 @@ void BKE_images_exit(void)
BLI_spin_end(&image_spin);
}
-/* ******** IMAGE PROCESSING ************* */
-
-static void de_interlace_ng(struct ImBuf *ibuf) /* neogeo fields */
-{
- struct ImBuf *tbuf1, *tbuf2;
-
- if (ibuf == NULL) return;
- if (ibuf->flags & IB_fields) return;
- ibuf->flags |= IB_fields;
-
- if (ibuf->rect) {
- /* make copies */
- tbuf1 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, (int)IB_rect);
- tbuf2 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, (int)IB_rect);
-
- ibuf->x *= 2;
-
- IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
- IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
-
- ibuf->x /= 2;
- IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
- IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y);
-
- IMB_freeImBuf(tbuf1);
- IMB_freeImBuf(tbuf2);
- }
- ibuf->y /= 2;
-}
-
-static void de_interlace_st(struct ImBuf *ibuf) /* standard fields */
-{
- struct ImBuf *tbuf1, *tbuf2;
-
- if (ibuf == NULL) return;
- if (ibuf->flags & IB_fields) return;
- ibuf->flags |= IB_fields;
-
- if (ibuf->rect) {
- /* make copies */
- tbuf1 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, IB_rect);
- tbuf2 = IMB_allocImBuf(ibuf->x, (ibuf->y >> 1), (unsigned char)32, IB_rect);
-
- ibuf->x *= 2;
-
- IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
- IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
-
- ibuf->x /= 2;
- IMB_rectcpy(ibuf, tbuf2, 0, 0, 0, 0, tbuf2->x, tbuf2->y);
- IMB_rectcpy(ibuf, tbuf1, 0, tbuf2->y, 0, 0, tbuf1->x, tbuf1->y);
-
- IMB_freeImBuf(tbuf1);
- IMB_freeImBuf(tbuf2);
- }
- ibuf->y /= 2;
-}
-
-void BKE_image_de_interlace(Image *ima, int odd)
-{
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ibuf) {
- if (odd)
- de_interlace_st(ibuf);
- else
- de_interlace_ng(ibuf);
- }
- BKE_image_release_ibuf(ima, ibuf, NULL);
-}
-
/* ***************** ALLOC & FREE, DATA MANAGING *************** */
static void image_free_cached_frames(Image *image)
@@ -341,19 +271,18 @@ void BKE_image_free_buffers(Image *ima)
/** Free (or release) any data used by this image (does not free the image itself). */
void BKE_image_free(Image *ima)
{
- int a;
-
/* Also frees animdata. */
BKE_image_free_buffers(ima);
image_free_packedfiles(ima);
- for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) {
- if (ima->renders[a]) {
- RE_FreeRenderResult(ima->renders[a]);
- ima->renders[a] = NULL;
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima->renderslots) {
+ if (slot->render) {
+ RE_FreeRenderResult(slot->render);
+ slot->render = NULL;
}
}
+ BLI_freelistN(&ima->renderslots);
BKE_image_free_views(ima);
MEM_SAFE_FREE(ima->stereo3d_format);
@@ -369,7 +298,6 @@ static void image_init(Image *ima, short source, short type)
ima->ok = IMA_OK;
- ima->xrep = ima->yrep = 1;
ima->aspx = ima->aspy = 1.0;
ima->gen_x = 1024; ima->gen_y = 1024;
ima->gen_type = IMA_GENTYPE_GRID;
@@ -380,6 +308,12 @@ static void image_init(Image *ima, short source, short type)
if (source == IMA_SRC_VIEWER)
ima->flag |= IMA_VIEW_AS_RENDER;
+ if (type == IMA_TYPE_R_RESULT) {
+ for (int i = 0; i < 8; i++) {
+ BKE_image_add_renderslot(ima, NULL);
+ }
+ }
+
BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings);
ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format");
}
@@ -466,18 +400,17 @@ void BKE_image_copy_data(Main *UNUSED(bmain), Image *ima_dst, const Image *ima_s
/* Cleanup stuff that cannot be copied. */
ima_dst->cache = NULL;
ima_dst->rr = NULL;
- for (int i = 0; i < IMA_MAX_RENDER_SLOT; i++) {
- ima_dst->renders[i] = NULL;
+
+ BLI_duplicatelist(&ima_dst->renderslots, &ima_src->renderslots);
+ LISTBASE_FOREACH(RenderSlot *, slot, &ima_dst->renderslots) {
+ slot->render = NULL;
}
BLI_listbase_clear(&ima_dst->anims);
- ima_dst->totbind = 0;
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- ima_dst->bindcode[i] = 0;
ima_dst->gputexture[i] = NULL;
}
- ima_dst->repbind = NULL;
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
BKE_previewimg_id_copy(&ima_dst->id, &ima_src->id);
@@ -540,16 +473,14 @@ bool BKE_image_scale(Image *image, int width, int height)
return (ibuf != NULL);
}
-bool BKE_image_has_bindcode(Image *ima)
+bool BKE_image_has_opengl_texture(Image *ima)
{
- bool has_bindcode = false;
for (int i = 0; i < TEXTARGET_COUNT; i++) {
- if (ima->bindcode[i]) {
- has_bindcode = true;
- break;
+ if (ima->gputexture[i]) {
+ return true;
}
}
- return has_bindcode;
+ return false;
}
static void image_init_color_management(Image *ima)
@@ -932,21 +863,6 @@ void BKE_image_tag_time(Image *ima)
ima->lastused = PIL_check_seconds_timer_i();
}
-#if 0
-static void tag_all_images_time(Main *bmain)
-{
- Image *ima;
- int ctime = PIL_check_seconds_timer_i();
-
- ima = bmain->image.first;
- while (ima) {
- if (ima->bindcode || ima->repbind || ima->ibufs.first) {
- ima->lastused = ctime;
- }
- }
-}
-#endif
-
static uintptr_t image_mem_size(Image *image)
{
uintptr_t size = 0;
@@ -1208,7 +1124,6 @@ bool BKE_imtype_is_movie(const char imtype)
case R_IMF_IMTYPE_H264:
case R_IMF_IMTYPE_THEORA:
case R_IMF_IMTYPE_XVID:
- case R_IMF_IMTYPE_FRAMESERVER:
return true;
}
return false;
@@ -1349,7 +1264,6 @@ char BKE_imtype_from_arg(const char *imtype_arg)
else if (STREQ(imtype_arg, "MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER;
#endif
else if (STREQ(imtype_arg, "FFMPEG")) return R_IMF_IMTYPE_FFMPEG;
- else if (STREQ(imtype_arg, "FRAMESERVER")) return R_IMF_IMTYPE_FRAMESERVER;
#ifdef WITH_CINEON
else if (STREQ(imtype_arg, "CINEON")) return R_IMF_IMTYPE_CINEON;
else if (STREQ(imtype_arg, "DPX")) return R_IMF_IMTYPE_DPX;
@@ -2654,19 +2568,19 @@ void BKE_image_walk_all_users(const Main *mainp, void *customdata,
}
}
+ for (Camera *cam = mainp->camera.first; cam; cam = cam->id.next) {
+ for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ callback(bgpic->ima, &bgpic->iuser, customdata);
+ }
+ }
+
/* image window, compo node users */
for (wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
- BGpic *bgpic;
- for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
- callback(bgpic->ima, &bgpic->iuser, customdata);
- }
- }
- else if (sa->spacetype == SPACE_IMAGE) {
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_IMAGE) {
SpaceImage *sima = sa->spacedata.first;
callback(sima->image, &sima->iuser, customdata);
}
@@ -2756,11 +2670,6 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
ima->name[0] = '\0';
}
-#if 0
- /* force reload on first use, but not for multilayer, that makes nodes and buttons in ui drawing fail */
- if (ima->type != IMA_TYPE_MULTILAYER)
- BKE_image_free_buffers(ima);
-#else
/* image buffers for non-sequence multilayer will share buffers with RenderResult,
* however sequence multilayer will own buffers. Such logic makes switching from
* single multilayer file to sequence completely unstable
@@ -2769,7 +2678,6 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
* sequences behave stable
*/
BKE_image_free_buffers(ima);
-#endif
ima->ok = 1;
if (iuser)
@@ -3019,7 +2927,7 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima)
if (ima->render_slot == ima->last_render_slot)
rr = RE_AcquireResultRead(RE_GetSceneRender(scene));
else
- rr = ima->renders[ima->render_slot];
+ rr = BKE_image_get_renderslot(ima, ima->render_slot)->render;
/* set proper views */
image_init_multilayer_multiview(ima, rr);
@@ -3053,27 +2961,39 @@ bool BKE_image_is_openexr(struct Image *ima)
void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
{
- /* called right before rendering, ima->renders contains render
+ /* called right before rendering, ima->renderslots contains render
* result pointers for everything but the current render */
Render *re = RE_GetSceneRender(scene);
- int slot = ima->render_slot, last = ima->last_render_slot;
- if (slot != last) {
- ima->renders[last] = NULL;
- RE_SwapResult(re, &ima->renders[last]);
+ /* Ensure we always have a valid render slot. */
+ if (!ima->renderslots.first) {
+ BKE_image_add_renderslot(ima, NULL);
+ ima->render_slot = 0;
+ ima->last_render_slot = 0;
+ }
+ else if (ima->render_slot >= BLI_listbase_count(&ima->renderslots)) {
+ ima->render_slot = 0;
+ ima->last_render_slot = 0;
+ }
+
+ RenderSlot *last_slot = BKE_image_get_renderslot(ima, ima->last_render_slot);
+ RenderSlot *cur_slot = BKE_image_get_renderslot(ima, ima->render_slot);
- if (ima->renders[slot]) {
+ if (last_slot && ima->render_slot != ima->last_render_slot) {
+ last_slot->render = NULL;
+ RE_SwapResult(re, &last_slot->render);
+
+ if (cur_slot->render) {
if (free_current_slot) {
- RE_FreeRenderResult(ima->renders[slot]);
- ima->renders[slot] = NULL;
+ BKE_image_clear_renderslot(ima, NULL, ima->render_slot);
}
else {
- RE_SwapResult(re, &ima->renders[slot]);
+ RE_SwapResult(re, &cur_slot->render);
}
}
}
- ima->last_render_slot = slot;
+ ima->last_render_slot = ima->render_slot;
}
/**************************** multiview load openexr *********************************/
@@ -3132,7 +3052,7 @@ static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
#endif /* WITH_OPENEXR */
/* common stuff to do with images after loading */
-static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
+static void image_initialize_after_load(Image *ima, ImBuf *UNUSED(ibuf))
{
/* Preview is NULL when it has never been used as an icon before.
* Never handle previews/icons outside of main thread. */
@@ -3140,11 +3060,6 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
}
- /* fields */
- if (ima->flag & IMA_FIELDS) {
- if (ima->flag & IMA_STD_FIELD) de_interlace_st(ibuf);
- else de_interlace_ng(ibuf);
- }
/* timer */
BKE_image_tag_time(ima);
@@ -3495,7 +3410,7 @@ static ImBuf *load_image_single(
flag |= imbuf_alpha_flags_for_image(ima);
/* get the correct filepath */
- BKE_image_user_frame_calc(iuser, cfra, 0);
+ BKE_image_user_frame_calc(iuser, cfra);
if (iuser)
iuser_t = *iuser;
@@ -3528,9 +3443,6 @@ static ImBuf *load_image_single(
image_initialize_after_load(ima, ibuf);
*r_assign = true;
- /* check if the image is a font image... */
- detectBitmapFont(ibuf);
-
/* make packed file for autopack */
if ((has_packed == false) && (G.fileflags & G_AUTOPACK)) {
ImagePackedFile *imapf = MEM_mallocN(sizeof(ImagePackedFile), "Image Packefile");
@@ -3691,11 +3603,12 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
if (BKE_image_is_stereo(ima) && (iuser->flag & IMA_SHOW_STEREO))
actview = iuser->multiview_eye;
+ RenderSlot *slot;
if (from_render) {
RE_AcquireResultImage(re, &rres, actview);
}
- else if (ima->renders[ima->render_slot]) {
- rres = *(ima->renders[ima->render_slot]);
+ else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) {
+ rres = *(slot->render);
rres.have_combined = ((RenderView *)rres.views.first)->rectf != NULL;
}
else
@@ -4249,9 +4162,9 @@ void BKE_image_pool_release_ibuf(Image *ima, ImBuf *ibuf, ImagePool *pool)
}
}
-int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool *r_is_in_range)
+int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, bool *r_is_in_range)
{
- const int len = (iuser->fie_ima * iuser->frames) / 2;
+ const int len = iuser->frames;
if (r_is_in_range) {
*r_is_in_range = false;
@@ -4287,12 +4200,8 @@ int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool
}
}
- /* convert current frame to current field */
- cfra = 2 * (cfra);
- if (fieldnr) cfra++;
-
/* transform to images space */
- framenr = (cfra + iuser->fie_ima - 2) / iuser->fie_ima;
+ framenr = cfra;
if (framenr > iuser->frames) framenr = iuser->frames;
if (iuser->cycl) {
@@ -4308,11 +4217,11 @@ int BKE_image_user_frame_get(const ImageUser *iuser, int cfra, int fieldnr, bool
}
}
-void BKE_image_user_frame_calc(ImageUser *iuser, int cfra, int fieldnr)
+void BKE_image_user_frame_calc(ImageUser *iuser, int cfra)
{
if (iuser) {
bool is_in_range;
- const int framenr = BKE_image_user_frame_get(iuser, cfra, fieldnr, &is_in_range);
+ const int framenr = BKE_image_user_frame_get(iuser, cfra, &is_in_range);
if (is_in_range) {
iuser->flag |= IMA_USER_FRAME_IN_RANGE;
@@ -4331,10 +4240,10 @@ void BKE_image_user_frame_calc(ImageUser *iuser, int cfra, int fieldnr)
}
}
-void BKE_image_user_check_frame_calc(ImageUser *iuser, int cfra, int fieldnr)
+void BKE_image_user_check_frame_calc(ImageUser *iuser, int cfra)
{
if ((iuser->flag & IMA_ANIM_ALWAYS) || (iuser->flag & IMA_NEED_FRAME_RECALC)) {
- BKE_image_user_frame_calc(iuser, cfra, fieldnr);
+ BKE_image_user_frame_calc(iuser, cfra);
iuser->flag &= ~IMA_NEED_FRAME_RECALC;
}
@@ -4345,7 +4254,7 @@ static void image_update_frame(struct Image *UNUSED(ima), struct ImageUser *iuse
{
int cfra = *(int *)customdata;
- BKE_image_user_check_frame_calc(iuser, cfra, 0);
+ BKE_image_user_check_frame_calc(iuser, cfra);
}
void BKE_image_update_frame(const Main *bmain, int cfra)
@@ -4553,15 +4462,6 @@ bool BKE_image_is_dirty(Image *image)
void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options)
{
-#if 0
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
- if (ibuf) {
- ibuf->ftype = ftype;
- ibuf->foptions = options;
- }
- BKE_image_release_ibuf(image, ibuf, NULL);
-#endif
-
BLI_spin_lock(&image_spin);
if (image->cache != NULL) {
struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache);
@@ -4725,3 +4625,97 @@ static void image_update_views_format(Image *ima, ImageUser *iuser)
}
}
}
+
+/**************************** Render Slots ***************************/
+
+RenderSlot *BKE_image_add_renderslot(Image *ima, const char *name)
+{
+ RenderSlot *slot = MEM_callocN(sizeof(RenderSlot), "Image new Render Slot");
+ if (name && name[0]) {
+ BLI_strncpy(slot->name, name, sizeof(slot->name));
+ }
+ else {
+ int n = BLI_listbase_count(&ima->renderslots) + 1;
+ BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", n);
+ }
+ BLI_addtail(&ima->renderslots, slot);
+ return slot;
+}
+
+bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int index)
+{
+ int num_slots = BLI_listbase_count(&ima->renderslots);
+ if (index >= num_slots || num_slots == 1) {
+ return false;
+ }
+
+ RenderSlot *remove_slot = BLI_findlink(&ima->renderslots, index);
+ RenderSlot *current_slot = BLI_findlink(&ima->renderslots, ima->render_slot);
+ RenderSlot *current_last_slot = BLI_findlink(&ima->renderslots, ima->last_render_slot);
+
+ RenderSlot *next_slot;
+ if (current_slot == remove_slot) {
+ next_slot = BLI_findlink(&ima->renderslots, (index == num_slots - 1) ? index - 1 : index + 1);
+ }
+ else {
+ next_slot = current_slot;
+ }
+
+ /* If the slot to be removed is the slot with the last render, make another slot the last render slot. */
+ if (remove_slot == current_last_slot) {
+ /* Choose the currently selected slot unless that one is being removed, in that case take the next one. */
+ RenderSlot *next_last_slot;
+ if (current_slot == remove_slot)
+ next_last_slot = next_slot;
+ else
+ next_last_slot = current_slot;
+
+ if (!iuser) return false;
+ Render *re = RE_GetSceneRender(iuser->scene);
+ if (!re) return false;
+ RE_SwapResult(re, &current_last_slot->render);
+ RE_SwapResult(re, &next_last_slot->render);
+ current_last_slot = next_last_slot;
+ }
+
+ current_slot = next_slot;
+
+ BLI_remlink(&ima->renderslots, remove_slot);
+
+ ima->render_slot = BLI_findindex(&ima->renderslots, current_slot);
+ ima->last_render_slot = BLI_findindex(&ima->renderslots, current_last_slot);
+
+ if (remove_slot->render) {
+ RE_FreeRenderResult(remove_slot->render);
+ }
+ MEM_freeN(remove_slot);
+
+ return true;
+}
+
+bool BKE_image_clear_renderslot(Image *ima, ImageUser *iuser, int index)
+{
+ if (index == ima->last_render_slot) {
+ if (!iuser) return false;
+ if (G.is_rendering) return false;
+ Render *re = RE_GetSceneRender(iuser->scene);
+ if (!re) return false;
+ RE_ClearResult(re);
+ return true;
+ }
+ else {
+ RenderSlot *slot = BLI_findlink(&ima->renderslots, index);
+ if (!slot) return false;
+ if (slot->render) {
+ RE_FreeRenderResult(slot->render);
+ slot->render = NULL;
+ }
+ return true;
+ }
+}
+
+RenderSlot *BKE_image_get_renderslot(Image *ima, int index)
+{
+ /* Can be NULL for images without render slots. */
+ return BLI_findlink(&ima->renderslots, index);
+}
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 7cb9ffc3611..c30a47b5435 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -46,7 +46,6 @@
/* since we have versioning code here */
#define DNA_DEPRECATED_ALLOW
-#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
#include "DNA_constraint_types.h"
#include "DNA_camera_types.h"
@@ -146,17 +145,6 @@ static AdrBit2Path ob_layer_bits[] = {
{(1 << 19), "layers", 19}
};
-/* Material mode */
-static AdrBit2Path ma_mode_bits[] = {
-// {MA_TRACEBLE, "traceable", 0},
-// {MA_SHADOW, "shadow", 0},
-// {MA_SHLESS, "shadeless", 0},
-// ...
- {MA_RAYTRANSP, "transparency", 0},
- {MA_RAYMIRROR, "raytrace_mirror.enabled", 0},
-// {MA_HALO, "type", MA_TYPE_HALO}
-};
-
/* ----------------- */
/* quick macro for returning the appropriate array for adrcode_bitmaps_to_paths() */
@@ -173,9 +161,6 @@ static AdrBit2Path *adrcode_bitmaps_to_paths(int blocktype, int adrcode, int *to
if ((blocktype == ID_OB) && (adrcode == OB_LAY)) {
RET_ABP(ob_layer_bits);
}
- else if ((blocktype == ID_MA) && (adrcode == MA_MODE)) {
- RET_ABP(ma_mode_bits);
- }
// XXX TODO: add other types...
/* Normal curve */
@@ -1767,23 +1752,6 @@ void do_versions_ipos_to_animato(Main *bmain)
ipo_to_animdata(bmain, id, ob->ipo, NULL, NULL, NULL);
/* No need to id_us_min ipo ID here, ipo_to_animdata already does it. */
ob->ipo = NULL;
-
- {
- /* If we have any empty action actuators, assume they were
- * converted IPO Actuators using the object IPO */
- bActuator *act;
- bActionActuator *aa;
-
- for (act = ob->actuators.first; act; act = act->next) {
- /* Any actuators set to ACT_IPO at this point are actually Action Actuators that
- * need this converted IPO to finish converting the actuator. */
- if (act->type == ACT_IPO) {
- aa = (bActionActuator *)act->data;
- aa->act = ob->adt->action;
- act->type = ACT_ACTION;
- }
- }
- }
}
}
@@ -2030,7 +1998,7 @@ void do_versions_ipos_to_animato(Main *bmain)
for (id = bmain->lamp.first; id; id = id->next) {
Lamp *la = (Lamp *)id;
- if (G.debug & G_DEBUG) printf("\tconverting lamp %s\n", id->name + 2);
+ if (G.debug & G_DEBUG) printf("\tconverting light %s\n", id->name + 2);
/* we're only interested in the IPO */
if (la->ipo) {
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 4689575655e..a01d78f5c36 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -76,6 +76,12 @@
#define IPO_BEZTRIPLE 100
#define IPO_BPOINT 101
+/* Internal use only. */
+typedef struct WeightsArrayCache {
+ int num_defgroup_weights;
+ float **defgroup_weights;
+} WeightsArrayCache;
+
/** Free (or release) any data used by this shapekey (does not free the key itself). */
void BKE_key_free(Key *key)
@@ -119,31 +125,31 @@ Key *BKE_key_add(Main *bmain, ID *id) /* common function */
case ID_ME:
el = key->elemstr;
- el[0] = 3;
+ el[0] = KEYELEM_FLOAT_LEN_COORD;
el[1] = IPO_FLOAT;
el[2] = 0;
- key->elemsize = 12;
+ key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
break;
case ID_LT:
el = key->elemstr;
- el[0] = 3;
+ el[0] = KEYELEM_FLOAT_LEN_COORD;
el[1] = IPO_FLOAT;
el[2] = 0;
- key->elemsize = 12;
+ key->elemsize = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
break;
case ID_CU:
el = key->elemstr;
- el[0] = 4;
+ el[0] = KEYELEM_ELEM_SIZE_CURVE;
el[1] = IPO_BPOINT;
el[2] = 0;
- key->elemsize = 16;
+ key->elemsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
break;
@@ -540,31 +546,33 @@ static char *key_block_get_data(Key *key, KeyBlock *actkb, KeyBlock *kb, char **
/* currently only the first value of 'ofs' may be set. */
-static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs)
+static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int *ofs, int *step)
{
if (key->from == NULL) {
return false;
}
+ *step = 1;
+
switch (GS(key->from->name)) {
case ID_ME:
- *ofs = sizeof(float) * 3;
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
*poinsize = *ofs;
break;
case ID_LT:
- *ofs = sizeof(float) * 3;
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
*poinsize = *ofs;
break;
case ID_CU:
if (mode == KEY_MODE_BPOINT) {
- *ofs = sizeof(float) * 4;
- *poinsize = *ofs;
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BPOINT]);
+ *step = KEYELEM_ELEM_LEN_BPOINT;
}
else {
- ofs[0] = sizeof(float) * 12;
- *poinsize = (*ofs) / 3;
+ *ofs = sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE]);
+ *step = KEYELEM_ELEM_LEN_BEZTRIPLE;
}
-
+ *poinsize = sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
break;
default:
BLI_assert(!"invalid 'key->from' ID type");
@@ -577,14 +585,14 @@ static bool key_pointer_size(const Key *key, const int mode, int *poinsize, int
static void cp_key(const int start, int end, const int tot, char *poin, Key *key, KeyBlock *actkb, KeyBlock *kb, float *weights, const int mode)
{
float ktot = 0.0, kd = 0.0;
- int elemsize, poinsize = 0, a, *ofsp, ofs[32], flagflo = 0;
+ int elemsize, poinsize = 0, a, step, *ofsp, ofs[32], flagflo = 0;
char *k1, *kref, *freek1, *freekref;
char *cp, elemstr[8];
/* currently always 0, in future key_pointer_size may assign */
ofs[1] = 0;
- if (!key_pointer_size(key, mode, &poinsize, &ofs[0]))
+ if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
return;
if (end > tot) end = tot;
@@ -628,10 +636,9 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key
}
/* just do it here, not above! */
- elemsize = key->elemsize;
- if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+ elemsize = key->elemsize * step;
- for (a = start; a < end; a++) {
+ for (a = start; a < end; a += step) {
cp = key->elemstr;
if (mode == KEY_MODE_BEZTRIPLE) cp = elemstr;
@@ -642,20 +649,20 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key
switch (cp[1]) {
case IPO_FLOAT:
if (weights) {
- memcpy(poin, kref, sizeof(float) * 3);
+ memcpy(poin, kref, sizeof(float[KEYELEM_FLOAT_LEN_COORD]));
if (*weights != 0.0f)
- rel_flerp(cp[0], (float *)poin, (float *)kref, (float *)k1, *weights);
+ rel_flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)kref, (float *)k1, *weights);
weights++;
}
else {
- memcpy(poin, k1, sizeof(float) * 3);
+ memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_COORD]));
}
break;
case IPO_BPOINT:
- memcpy(poin, k1, sizeof(float) * 4);
+ memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BPOINT]));
break;
case IPO_BEZTRIPLE:
- memcpy(poin, k1, sizeof(float) * 12);
+ memcpy(poin, k1, sizeof(float[KEYELEM_FLOAT_LEN_BEZTRIPLE]));
break;
default:
/* should never happen */
@@ -682,10 +689,6 @@ static void cp_key(const int start, int end, const int tot, char *poin, Key *key
k1 += elemsize;
kref += elemsize;
}
-
- if (mode == KEY_MODE_BEZTRIPLE) {
- a += 2;
- }
}
if (freek1) MEM_freeN(freek1);
@@ -699,7 +702,7 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const
for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
if (nu->bp) {
- step = nu->pntsu * nu->pntsv;
+ step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
a1 = max_ii(a, start);
a2 = min_ii(a + step, end);
@@ -707,7 +710,7 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const
if (a1 < a2) cp_key(a1, a2, tot, out, key, actkb, kb, NULL, KEY_MODE_BPOINT);
}
else if (nu->bezt) {
- step = 3 * nu->pntsu;
+ step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
/* exception because keys prefer to work with complete blocks */
a1 = max_ii(a, start);
@@ -721,18 +724,19 @@ static void cp_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock *kb, const
}
}
-void BKE_key_evaluate_relative(const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
- float **per_keyblock_weights, const int mode)
+static void key_evaluate_relative(
+ const int start, int end, const int tot, char *basispoin, Key *key, KeyBlock *actkb,
+ float **per_keyblock_weights, const int mode)
{
KeyBlock *kb;
- int *ofsp, ofs[3], elemsize, b;
+ int *ofsp, ofs[3], elemsize, b, step;
char *cp, *poin, *reffrom, *from, elemstr[8];
int poinsize, keyblock_index;
/* currently always 0, in future key_pointer_size may assign */
ofs[1] = 0;
- if (!key_pointer_size(key, mode, &poinsize, &ofs[0]))
+ if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
return;
if (end > tot) end = tot;
@@ -743,8 +747,7 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
elemstr[2] = 0;
/* just here, not above! */
- elemsize = key->elemsize;
- if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
+ elemsize = key->elemsize * step;
/* step 1 init */
cp_key(start, end, tot, basispoin, key, actkb, key->refkey, NULL, mode);
@@ -773,7 +776,7 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
reffrom += key->elemsize * start; // key elemsize yes!
from += key->elemsize * start;
- for (b = start; b < end; b++) {
+ for (b = start; b < end; b += step) {
weight = weights ? (*weights * icuval) : icuval;
@@ -786,13 +789,13 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
switch (cp[1]) {
case IPO_FLOAT:
- rel_flerp(3, (float *)poin, (float *)reffrom, (float *)from, weight);
+ rel_flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)reffrom, (float *)from, weight);
break;
case IPO_BPOINT:
- rel_flerp(4, (float *)poin, (float *)reffrom, (float *)from, weight);
+ rel_flerp(KEYELEM_FLOAT_LEN_BPOINT, (float *)poin, (float *)reffrom, (float *)from, weight);
break;
case IPO_BEZTRIPLE:
- rel_flerp(12, (float *)poin, (float *)reffrom, (float *)from, weight);
+ rel_flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE, (float *)poin, (float *)reffrom, (float *)from, weight);
break;
default:
/* should never happen */
@@ -811,7 +814,6 @@ void BKE_key_evaluate_relative(const int start, int end, const int tot, char *ba
reffrom += elemsize;
from += elemsize;
- if (mode == KEY_MODE_BEZTRIPLE) b += 2;
if (weights) weights++;
}
@@ -827,7 +829,7 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
{
float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0;
float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0;
- int a, ofs[32], *ofsp;
+ int a, step, ofs[32], *ofsp;
int flagdo = 15, flagflo = 0, elemsize, poinsize = 0;
char *k1, *k2, *k3, *k4, *freek1, *freek2, *freek3, *freek4;
char *cp, elemstr[8];
@@ -835,7 +837,7 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
/* currently always 0, in future key_pointer_size may assign */
ofs[1] = 0;
- if (!key_pointer_size(key, mode, &poinsize, &ofs[0]))
+ if (!key_pointer_size(key, mode, &poinsize, &ofs[0], &step))
return;
if (end > tot) end = tot;
@@ -953,11 +955,9 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
elemstr[2] = 0;
/* only here, not above! */
- elemsize = key->elemsize;
- if (mode == KEY_MODE_BEZTRIPLE) elemsize *= 3;
-
- for (a = start; a < end; a++) {
+ elemsize = key->elemsize * step;
+ for (a = start; a < end; a += step) {
cp = key->elemstr;
if (mode == KEY_MODE_BEZTRIPLE) cp = elemstr;
@@ -967,13 +967,13 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
switch (cp[1]) {
case IPO_FLOAT:
- flerp(3, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
+ flerp(KEYELEM_FLOAT_LEN_COORD, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
break;
case IPO_BPOINT:
- flerp(4, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
+ flerp(KEYELEM_FLOAT_LEN_BPOINT, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
break;
case IPO_BEZTRIPLE:
- flerp(12, (void *)poin, (void *)k1, (void *)k2, (void *)k3, (void *)k4, t);
+ flerp(KEYELEM_FLOAT_LEN_BEZTRIPLE, (void *)poin, (void *)k1, (void *)k2, (void *)k3, (void *)k4, t);
break;
default:
/* should never happen */
@@ -1038,8 +1038,6 @@ static void do_key(const int start, int end, const int tot, char *poin, Key *key
k4 += elemsize;
}
}
-
- if (mode == KEY_MODE_BEZTRIPLE) a += 2;
}
if (freek1) MEM_freeN(freek1);
@@ -1120,7 +1118,7 @@ static float *get_weights_array(Object *ob, char *vgroup, WeightsArrayCache *cac
return NULL;
}
-float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache)
+static float **keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCache *cache)
{
KeyBlock *keyblock;
float **per_keyblock_weights;
@@ -1140,7 +1138,7 @@ float **BKE_keyblock_get_per_block_weights(Object *ob, Key *key, WeightsArrayCac
return per_keyblock_weights;
}
-void BKE_keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache)
+static void keyblock_free_per_block_weights(Key *key, float **per_keyblock_weights, WeightsArrayCache *cache)
{
int a;
@@ -1175,9 +1173,9 @@ static void do_mesh_key(Object *ob, Key *key, char *out, const int tot)
if (key->type == KEY_RELATIVE) {
WeightsArrayCache cache = {0, NULL};
float **per_keyblock_weights;
- per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, &cache);
- BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
- BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, &cache);
+ per_keyblock_weights = keyblock_get_per_block_weights(ob, key, &cache);
+ key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
+ keyblock_free_per_block_weights(key, per_keyblock_weights, &cache);
}
else {
const float ctime_scaled = key->ctime / 100.0f;
@@ -1200,11 +1198,11 @@ static void do_cu_key(Curve *cu, Key *key, KeyBlock *actkb, KeyBlock **k, float
for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
if (nu->bp) {
- step = nu->pntsu * nu->pntsv;
+ step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BPOINT);
}
else if (nu->bezt) {
- step = 3 * nu->pntsu;
+ step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
do_key(a, a + step, tot, out, key, actkb, k, t, KEY_MODE_BEZTRIPLE);
}
else {
@@ -1220,12 +1218,12 @@ static void do_rel_cu_key(Curve *cu, Key *key, KeyBlock *actkb, char *out, const
for (a = 0, nu = cu->nurb.first; nu; nu = nu->next, a += step) {
if (nu->bp) {
- step = nu->pntsu * nu->pntsv;
- BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT);
+ step = KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
+ key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BPOINT);
}
else if (nu->bezt) {
- step = 3 * nu->pntsu;
- BKE_key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE);
+ step = KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
+ key_evaluate_relative(a, a + step, tot, out, key, actkb, NULL, KEY_MODE_BEZTRIPLE);
}
else {
step = 0;
@@ -1266,9 +1264,9 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
if (key->type == KEY_RELATIVE) {
float **per_keyblock_weights;
- per_keyblock_weights = BKE_keyblock_get_per_block_weights(ob, key, NULL);
- BKE_key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
- BKE_keyblock_free_per_block_weights(key, per_keyblock_weights, NULL);
+ per_keyblock_weights = keyblock_get_per_block_weights(ob, key, NULL);
+ key_evaluate_relative(0, tot, tot, (char *)out, key, actkb, per_keyblock_weights, KEY_MODE_DUMMY);
+ keyblock_free_per_block_weights(key, per_keyblock_weights, NULL);
}
else {
const float ctime_scaled = key->ctime / 100.0f;
@@ -1304,28 +1302,19 @@ float *BKE_key_evaluate_object_ex(
Mesh *me = ob->data;
tot = me->totvert;
- size = tot * 3 * sizeof(float);
+ size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
tot = lt->pntsu * lt->pntsv * lt->pntsw;
- size = tot * 3 * sizeof(float);
+ size = tot * sizeof(float[KEYELEM_FLOAT_LEN_COORD]);
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
- Nurb *nu;
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->bezt) {
- tot += 3 * nu->pntsu;
- size += nu->pntsu * 12 * sizeof(float);
- }
- else if (nu->bp) {
- tot += nu->pntsu * nu->pntsv;
- size += nu->pntsu * nu->pntsv * 12 * sizeof(float);
- }
- }
+ tot = BKE_keyblock_curve_element_count(&cu->nurb);
+ size = tot * sizeof(float[KEYELEM_ELEM_SIZE_CURVE]);
}
/* if nothing to interpolate, cancel */
@@ -1457,7 +1446,7 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
kb = MEM_callocN(sizeof(KeyBlock), "Keyblock");
BLI_addtail(&key->block, kb);
- kb->type = KEY_CARDINAL;
+ kb->type = KEY_LINEAR;
tot = BLI_listbase_count(&key->block);
if (name) {
@@ -1661,6 +1650,24 @@ void BKE_keyblock_convert_to_lattice(KeyBlock *kb, Lattice *lt)
}
/************************* Curve ************************/
+
+int BKE_keyblock_curve_element_count(ListBase *nurb)
+{
+ Nurb *nu;
+ int tot = 0;
+
+ nu = nurb->first;
+ while (nu) {
+ if (nu->bezt)
+ tot += KEYELEM_ELEM_LEN_BEZTRIPLE * nu->pntsu;
+ else if (nu->bp)
+ tot += KEYELEM_ELEM_LEN_BPOINT * nu->pntsu * nu->pntsv;
+
+ nu = nu->next;
+ }
+ return tot;
+}
+
void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *nurb)
{
Nurb *nu;
@@ -1670,7 +1677,7 @@ void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *n
int a, tot;
/* count */
- BLI_assert(BKE_nurbList_verts_count(nurb) == kb->totelem);
+ BLI_assert(BKE_keyblock_curve_element_count(nurb) == kb->totelem);
tot = kb->totelem;
if (tot == 0) return;
@@ -1679,21 +1686,20 @@ void BKE_keyblock_update_from_curve(Curve *UNUSED(cu), KeyBlock *kb, ListBase *n
for (nu = nurb->first; nu; nu = nu->next) {
if (nu->bezt) {
for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3) {
- copy_v3_v3(fp, bezt->vec[i]);
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(&fp[i * 3], bezt->vec[i]);
}
- fp[0] = bezt->alfa;
- fp += 3; /* alphas */
+ fp[9] = bezt->alfa;
+ fp[10] = bezt->radius;
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
-
- ;
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, fp += 4, bp++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++) {
copy_v3_v3(fp, bp->vec);
fp[3] = bp->alfa;
+ fp[4] = bp->radius;
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -1704,7 +1710,7 @@ void BKE_keyblock_convert_from_curve(Curve *cu, KeyBlock *kb, ListBase *nurb)
int tot;
/* count */
- tot = BKE_nurbList_verts_count(nurb);
+ tot = BKE_keyblock_curve_element_count(nurb);
if (tot == 0) return;
MEM_SAFE_FREE(kb->data);
@@ -1723,26 +1729,27 @@ void BKE_keyblock_convert_to_curve(KeyBlock *kb, Curve *UNUSED(cu), ListBase *nu
const float *fp;
int a, tot;
- tot = BKE_nurbList_verts_count(nurb);
+ tot = BKE_keyblock_curve_element_count(nurb);
tot = min_ii(kb->totelem, tot);
fp = kb->data;
for (nu = nurb->first; nu && tot > 0; nu = nu->next) {
if (nu->bezt) {
- for (a = nu->pntsu, bezt = nu->bezt; a && tot > 0; a--, tot -= 3, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3) {
- copy_v3_v3(bezt->vec[i], fp);
+ for (a = nu->pntsu, bezt = nu->bezt; a && (tot -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0; a--, bezt++) {
+ for (int i = 0; i < 3; i++) {
+ copy_v3_v3(bezt->vec[i], &fp[i * 3]);
}
- bezt->alfa = fp[0];
- fp += 3; /* alphas */
+ bezt->alfa = fp[9];
+ bezt->radius = fp[10];
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a && tot; a--, tot--, fp += 4, bp++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a && (tot -= KEYELEM_ELEM_LEN_BPOINT) >= 0; a--, bp++) {
copy_v3_v3(bp->vec, fp);
bp->alfa = fp[3];
+ bp->radius = fp[4];
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -1767,16 +1774,16 @@ void BKE_keyblock_update_from_mesh(Mesh *me, KeyBlock *kb)
}
}
-void BKE_keyblock_convert_from_mesh(Mesh *me, KeyBlock *kb)
+void BKE_keyblock_convert_from_mesh(Mesh *me, Key *key, KeyBlock *kb)
{
- int tot = me->totvert;
+ const int len = me->totvert;
if (me->totvert == 0) return;
MEM_SAFE_FREE(kb->data);
- kb->data = MEM_mallocN(me->key->elemsize * tot, __func__);
- kb->totelem = tot;
+ kb->data = MEM_malloc_arrayN((size_t)len, (size_t)key->elemsize, __func__);
+ kb->totelem = len;
BKE_keyblock_update_from_mesh(me, kb);
}
@@ -1871,7 +1878,7 @@ void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
- BLI_assert(BKE_nurbList_verts_count(&cu->nurb) == kb->totelem);
+ BLI_assert(BKE_keyblock_curve_element_count(&cu->nurb) == kb->totelem);
}
else if (ob->type == OB_MESH) {
Mesh *me = ob->data;
@@ -1900,17 +1907,16 @@ void BKE_keyblock_update_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos)
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->bezt) {
for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3, co++) {
- copy_v3_v3(fp, *co);
+ for (int i = 0; i < 3; i++, co++) {
+ copy_v3_v3(&fp[i * 3], *co);
}
- fp += 3; /* skip alphas */
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, fp += 4, co++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) {
copy_v3_v3(fp, *co);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -1937,7 +1943,7 @@ void BKE_keyblock_convert_from_vertcos(Object *ob, KeyBlock *kb, float (*vertCos
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = (Curve *)ob->data;
elemsize = cu->key->elemsize;
- tot = BKE_nurbList_verts_count(&cu->nurb);
+ tot = BKE_keyblock_curve_element_count(&cu->nurb);
}
if (tot == 0) return;
@@ -1987,17 +1993,16 @@ float (*BKE_keyblock_convert_to_vertcos(Object *ob, KeyBlock *kb))[3]
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->bezt) {
for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3, co++) {
- copy_v3_v3(*co, fp);
+ for (int i = 0; i < 3; i++, co++) {
+ copy_v3_v3(*co, &fp[i * 3]);
}
- fp += 3; /* skip alphas */
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, fp += 4, co++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, co++) {
copy_v3_v3(*co, fp);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
@@ -2026,17 +2031,16 @@ void BKE_keyblock_update_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3])
for (nu = cu->nurb.first; nu; nu = nu->next) {
if (nu->bezt) {
for (a = nu->pntsu, bezt = nu->bezt; a; a--, bezt++) {
- int i;
-
- for (i = 0; i < 3; i++, fp += 3, ofs++) {
- add_v3_v3(fp, *ofs);
+ for (int i = 0; i < 3; i++, ofs++) {
+ add_v3_v3(&fp[i * 3], *ofs);
}
- fp += 3; /* skip alphas */
+ fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, fp += 4, ofs++) {
+ for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a; a--, bp++, ofs++) {
add_v3_v3(fp, *ofs);
+ fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index b8ebdd9cda5..2c1b36d3496 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -59,47 +59,36 @@ void BKE_lamp_init(Lamp *la)
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(la, id));
la->r = la->g = la->b = la->k = 1.0f;
- la->haint = la->energy = 1.0f;
+ la->energy = 10.0f;
la->dist = 25.0f;
la->spotsize = DEG2RADF(45.0f);
la->spotblend = 0.15f;
la->att2 = 1.0f;
- la->mode = LA_SHAD_BUF;
+ la->mode = LA_SHADOW;
la->bufsize = 512;
la->clipsta = 0.5f;
la->clipend = 40.0f;
+ la->bleedexp = 2.5f;
la->samp = 3;
la->bias = 1.0f;
la->soft = 3.0f;
- la->compressthresh = 0.05f;
- la->ray_samp = la->ray_sampy = la->ray_sampz = 1;
- la->area_size = la->area_sizey = la->area_sizez = 0.1f;
+ la->area_size = la->area_sizey = la->area_sizez = 0.25f;
la->buffers = 1;
- la->buftype = LA_SHADBUF_HALFWAY;
- la->ray_samp_method = LA_SAMP_HALTON;
- la->adapt_thresh = 0.001f;
la->preview = NULL;
la->falloff_type = LA_FALLOFF_INVSQUARE;
la->coeff_const = 1.0f;
la->coeff_lin = 0.0f;
la->coeff_quad = 0.0f;
la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
- la->sun_effect_type = 0;
- la->horizon_brightness = 1.0;
- la->spread = 1.0;
- la->sun_brightness = 1.0;
- la->sun_size = 1.0;
- la->backscattered_light = 1.0f;
- la->atm_turbidity = 2.0f;
- la->atm_inscattering_factor = 1.0f;
- la->atm_extinction_factor = 1.0f;
- la->atm_distance_factor = 1.0f;
- la->sun_intensity = 1.0f;
- la->skyblendtype = MA_RAMP_ADD;
- la->skyblendfac = 1.0f;
- la->sky_colorspace = BLI_XYZ_CIE;
- la->sky_exposure = 1.0f;
- la->shadow_frustum_size = 10.0f;
+ la->cascade_max_dist = 1000.0f;
+ la->cascade_count = 4;
+ la->cascade_exponent = 0.8f;
+ la->cascade_fade = 0.1f;
+ la->contact_dist = 0.2f;
+ la->contact_bias = 0.03f;
+ la->contact_spread = 0.2f;
+ la->contact_thickness = 0.2f;
+ la->spec_fac = 1.0f;
curvemapping_initialize(la->curfalloff);
}
@@ -125,13 +114,6 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name)
*/
void BKE_lamp_copy_data(Main *bmain, Lamp *la_dst, const Lamp *la_src, const int flag)
{
- for (int a = 0; a < MAX_MTEX; a++) {
- if (la_dst->mtex[a]) {
- la_dst->mtex[a] = MEM_mallocN(sizeof(*la_dst->mtex[a]), __func__);
- *la_dst->mtex[a] = *la_src->mtex[a];
- }
- }
-
la_dst->curfalloff = curvemapping_copy(la_src->curfalloff);
if (la_src->nodetree) {
@@ -164,17 +146,7 @@ Lamp *BKE_lamp_localize(Lamp *la)
*
* ... Once f*** nodes are fully converted to that too :( */
- Lamp *lan;
- int a;
-
- lan = BKE_libblock_copy_nolib(&la->id, false);
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (lan->mtex[a]) {
- lan->mtex[a] = MEM_mallocN(sizeof(MTex), __func__);
- memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex));
- }
- }
+ Lamp *lan = BKE_libblock_copy_nolib(&la->id, false);
lan->curfalloff = curvemapping_copy(la->curfalloff);
@@ -193,12 +165,6 @@ void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local)
void BKE_lamp_free(Lamp *la)
{
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(la->mtex[a]);
- }
-
BKE_animdata_free((ID *)la, false);
curvemapping_free(la->curfalloff);
@@ -214,40 +180,3 @@ void BKE_lamp_free(Lamp *la)
BKE_icon_id_delete(&la->id);
la->id.icon_id = 0;
}
-
-/* Calculate all drivers for lamps, see material_drivers_update for why this is a bad hack */
-
-static void lamp_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime)
-{
- bNode *node;
-
- /* nodetree itself */
- if (ntree->adt && ntree->adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS);
-
- /* nodes */
- for (node = ntree->nodes.first; node; node = node->next)
- if (node->id && node->type == NODE_GROUP)
- lamp_node_drivers_update(scene, (bNodeTree *)node->id, ctime);
-}
-
-void lamp_drivers_update(Scene *scene, Lamp *la, float ctime)
-{
- /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited already
- * (see BKE_scene_update_tagged()). This assumes la->id.tag & LIB_TAG_DOIT isn't set by anything else
- * in the meantime... [#32017] */
- if (la->id.tag & LIB_TAG_DOIT)
- return;
-
- la->id.tag |= LIB_TAG_DOIT;
-
- /* lamp itself */
- if (la->adt && la->adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, &la->id, la->adt, ctime, ADT_RECALC_DRIVERS);
-
- /* nodes */
- if (la->nodetree)
- lamp_node_drivers_update(scene, la->nodetree, ctime);
-
- la->id.tag &= ~LIB_TAG_DOIT;
-}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 1e99712f47a..a04f32adece 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -53,7 +53,6 @@
#include "BKE_anim.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
@@ -66,10 +65,7 @@
#include "BKE_deform.h"
-/* Workaround for cyclic dependency with curves.
- * In such case curve_cache might not be ready yet,
- */
-#define CYCLIC_DEPENDENCY_WORKAROUND
+#include "DEG_depsgraph_query.h"
int BKE_lattice_index_from_uvw(Lattice *lt,
const int u, const int v, const int w)
@@ -215,9 +211,9 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
/* works best if we force to linear type (endpoints match) */
lt->typeu = lt->typev = lt->typew = KEY_LINEAR;
- /* prevent using deformed locations */
- if (ltOb->curve_cache != NULL) {
- BKE_displist_free(&ltOb->curve_cache->disp);
+ if (ltOb->runtime.curve_cache) {
+ /* prevent using deformed locations */
+ BKE_displist_free(&ltOb->runtime.curve_cache->disp);
}
copy_m4_m4(mat, ltOb->obmat);
@@ -290,7 +286,7 @@ void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src,
{
lt_dst->def = MEM_dupallocN(lt_src->def);
- if (lt_src->key) {
+ if (lt_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &lt_src->key->id, (ID **)&lt_dst->key, flag, false);
}
@@ -306,7 +302,7 @@ void BKE_lattice_copy_data(Main *bmain, Lattice *lt_dst, const Lattice *lt_src,
Lattice *BKE_lattice_copy(Main *bmain, const Lattice *lt)
{
Lattice *lt_copy;
- BKE_id_copy_ex(bmain, &lt->id, (ID **)&lt_copy, 0, false);
+ BKE_id_copy_ex(bmain, &lt->id, (ID **)&lt_copy, LIB_ID_COPY_SHAPEKEY, false);
return lt_copy;
}
@@ -315,6 +311,8 @@ void BKE_lattice_free(Lattice *lt)
{
BKE_animdata_free(&lt->id, false);
+ BKE_lattice_batch_cache_free(lt);
+
MEM_SAFE_FREE(lt->def);
if (lt->dvert) {
BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
@@ -351,7 +349,7 @@ LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob)
/* we make an array with all differences */
Lattice *lt = oblatt->data;
BPoint *bp;
- DispList *dl = oblatt->curve_cache ? BKE_displist_find(&oblatt->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = oblatt->runtime.curve_cache ? BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) : NULL;
const float *co = dl ? dl->verts : NULL;
float *fp, imat[4][4];
float fu, fv, fw;
@@ -422,10 +420,11 @@ void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float
int defgrp_index = -1;
float co_prev[3], weight_blend = 0.0f;
MDeformVert *dvert = BKE_lattice_deform_verts_get(ob);
+ float *__restrict latticedata = lattice_deform_data->latticedata;
if (lt->editlatt) lt = lt->editlatt->latt;
- if (lattice_deform_data->latticedata == NULL) return;
+ if (latticedata == NULL) return;
if (lt->vgroup[0] && dvert) {
defgrp_index = defgroup_name_index(ob, lt->vgroup);
@@ -506,7 +505,7 @@ void calc_latt_deform(LatticeDeformData *lattice_deform_data, float co[3], float
idx_u = idx_v;
}
- madd_v3_v3fl(co, &lattice_deform_data->latticedata[idx_u * 3], u);
+ madd_v3_v3fl(co, &latticedata[idx_u * 3], u);
if (defgrp_index != -1)
weight_blend += (u * defvert_find_weight(dvert + idx_u, defgrp_index));
@@ -559,7 +558,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
int cycl = 0;
/* test for cyclic */
- bl = ob->curve_cache->bev.first;
+ bl = ob->runtime.curve_cache->bev.first;
if (!bl->nr) return false;
if (bl->poly > -1) cycl = 1;
@@ -574,7 +573,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) {
if (cycl == 0) {
- Path *path = ob->curve_cache->path;
+ Path *path = ob->runtime.curve_cache->path;
float dvec[3];
if (ctime < 0.0f) {
@@ -603,7 +602,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di
/* co: local coord, result local too */
/* returns quaternion for rotation, using cd->no_rot_axis */
/* axis is using another define!!! */
-static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
+static bool calc_curve_deform(Object *par, float co[3],
const short axis, CurveDeform *cd, float r_quat[4])
{
Curve *cu = par->data;
@@ -611,14 +610,12 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
short index;
const bool is_neg_axis = (axis > 2);
- /* to be sure, mostly after file load, also cyclic dependencies */
-#ifdef CYCLIC_DEPENDENCY_WORKAROUND
- if (par->curve_cache == NULL) {
- BKE_displist_make_curveTypes(scene, par, false);
+ if (par->runtime.curve_cache == NULL) {
+ /* Happens with a cyclic dependencies. */
+ return false;
}
-#endif
- if (par->curve_cache->path == NULL) {
+ if (par->runtime.curve_cache->path == NULL) {
return false; /* happens on append, cyclic dependencies and empty curves */
}
@@ -628,7 +625,7 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
if (cu->flag & CU_STRETCH)
fac = -(co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]);
else
- fac = -(co[index] - cd->dmax[index]) / (par->curve_cache->path->totdist);
+ fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist);
}
else {
index = axis;
@@ -636,8 +633,8 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]);
}
else {
- if (LIKELY(par->curve_cache->path->totdist > FLT_EPSILON)) {
- fac = +(co[index] - cd->dmin[index]) / (par->curve_cache->path->totdist);
+ if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) {
+ fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist);
}
else {
fac = 0.0f;
@@ -707,7 +704,7 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
}
void curve_deform_verts(
- Scene *scene, Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3],
+ Object *cuOb, Object *target, Mesh *mesh, float (*vertexCos)[3],
int numVerts, const char *vgroup, short defaxis)
{
Curve *cu;
@@ -743,8 +740,8 @@ void curve_deform_verts(
if (defgrp_index != -1) {
/* if there's derived data without deformverts, don't use vgroups */
- if (dm) {
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ if (mesh) {
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
}
else if (target->type == OB_LATTICE) {
dvert = ((Lattice *)target->data)->dvert;
@@ -766,7 +763,7 @@ void curve_deform_verts(
if (weight > 0.0f) {
mul_m4_v3(cd.curvespace, vertexCos[a]);
copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
@@ -789,7 +786,7 @@ void curve_deform_verts(
if (weight > 0.0f) {
/* already in 'cd.curvespace', prev for loop */
copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vec, defaxis, &cd, NULL);
interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
@@ -800,7 +797,7 @@ void curve_deform_verts(
if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
for (a = 0; a < numVerts; a++) {
mul_m4_v3(cd.curvespace, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
}
@@ -815,7 +812,7 @@ void curve_deform_verts(
for (a = 0; a < numVerts; a++) {
/* already in 'cd.curvespace', prev for loop */
- calc_curve_deform(scene, cuOb, vertexCos[a], defaxis, &cd, NULL);
+ calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd, NULL);
mul_m4_v3(cd.objectspace, vertexCos[a]);
}
}
@@ -825,7 +822,7 @@ void curve_deform_verts(
/* input vec and orco = local coord in armature space */
/* orco is original not-animated or deformed reference point */
/* result written in vec and mat */
-void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
+void curve_deform_vector(Object *cuOb, Object *target,
float orco[3], float vec[3], float mat[3][3], int no_rot_axis)
{
CurveDeform cd;
@@ -844,7 +841,7 @@ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
mul_m4_v3(cd.curvespace, vec);
- if (calc_curve_deform(scene, cuOb, vec, target->trackflag, &cd, quat)) {
+ if (calc_curve_deform(cuOb, vec, target->trackflag, &cd, quat)) {
float qmat[3][3];
quat_to_mat3(qmat, quat);
@@ -857,7 +854,7 @@ void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
}
-void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
+void lattice_deform_verts(Object *laOb, Object *target, Mesh *mesh,
float (*vertexCos)[3], int numVerts, const char *vgroup, float fac)
{
LatticeDeformData *lattice_deform_data;
@@ -878,8 +875,8 @@ void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
if (defgrp_index != -1) {
/* if there's derived data without deformverts, don't use vgroups */
- if (dm) {
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ if (mesh) {
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
}
else if (target->type == OB_LATTICE) {
dvert = ((Lattice *)target->data)->dvert;
@@ -1027,47 +1024,54 @@ void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3])
}
}
-void BKE_lattice_modifiers_calc(Scene *scene, Object *ob)
+void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
Lattice *lt = ob->data;
+ /* Get vertex coordinates from the original copy; otherwise we get already-modified coordinates. */
+ Object *ob_orig = DEG_get_original_object(ob);
VirtualModifierData virtualModifierData;
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
float (*vertexCos)[3] = NULL;
int numVerts, editmode = (lt->editlatt != NULL);
+ const ModifierEvalContext mectx = {depsgraph, ob, 0};
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
}
else {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
+ ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice");
}
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if (!(mti->flags & eModifierTypeFlag_AcceptsLattice)) continue;
if (!(md->mode & eModifierMode_Realtime)) continue;
if (editmode && !(md->mode & eModifierMode_Editmode)) continue;
- if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue;
if (mti->type != eModifierTypeType_OnlyDeform) continue;
- if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts);
- mti->deformVerts(md, ob, NULL, vertexCos, numVerts, 0);
+ if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
+ mti->deformVerts(md, &mectx, NULL, vertexCos, numVerts);
}
- /* always displist to make this work like derivedmesh */
- if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob, &numVerts);
+ if (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) {
+ if (vertexCos) {
+ BKE_lattice_vertexcos_apply(ob, vertexCos);
+ MEM_freeN(vertexCos);
+ }
+ }
+ else {
+ /* Displist won't do anything; this is just for posterity's sake until we remove it. */
+ if (!vertexCos) vertexCos = BKE_lattice_vertexcos_get(ob_orig, &numVerts);
- {
DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
dl->type = DL_VERTS;
dl->parts = 1;
dl->nr = numVerts;
dl->verts = (float *) vertexCos;
- BLI_addtail(&ob->curve_cache->disp, dl);
+ BLI_addtail(&ob->runtime.curve_cache->disp, dl);
}
}
@@ -1141,7 +1145,7 @@ BoundBox *BKE_lattice_boundbox_get(Object *ob)
void BKE_lattice_minmax_dl(Object *ob, Lattice *lt, float min[3], float max[3])
{
- DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL;
if (!dl) {
BKE_lattice_minmax(lt, min, max);
@@ -1226,9 +1230,42 @@ void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
}
}
+bool BKE_lattice_is_any_selected(const Lattice *lt)
+{
+ /* Intentionally don't handle 'lt->editlatt' (caller must do this). */
+ const BPoint *bp = lt->def;
+ int a = lt->pntsu * lt->pntsv * lt->pntsw;
+ while (a--) {
+ if (bp->hide == 0) {
+ if (bp->f1 & SELECT) {
+ return true;
+ }
+ }
+ bp++;
+ }
+ return false;
+}
+
/* **** Depsgraph evaluation **** */
-void BKE_lattice_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
+void BKE_lattice_eval_geometry(struct Depsgraph *UNUSED(depsgraph),
Lattice *UNUSED(latt))
{
}
+
+/* Draw Engine */
+void (*BKE_lattice_batch_cache_dirty_tag_cb)(Lattice *lt, int mode) = NULL;
+void (*BKE_lattice_batch_cache_free_cb)(Lattice *lt) = NULL;
+
+void BKE_lattice_batch_cache_dirty_tag(Lattice *lt, int mode)
+{
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_dirty_tag_cb(lt, mode);
+ }
+}
+void BKE_lattice_batch_cache_free(Lattice *lt)
+{
+ if (lt->batch_cache) {
+ BKE_lattice_batch_cache_free_cb(lt);
+ }
+}
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
new file mode 100644
index 00000000000..fbfa47c8939
--- /dev/null
+++ b/source/blender/blenkernel/intern/layer.c
@@ -0,0 +1,1479 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/layer.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_array.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLI_threads.h"
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
+#include "BKE_collection.h"
+#include "BKE_freestyle.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_layer.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+
+#include "DNA_ID.h"
+#include "DNA_collection_types.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DRW_engine.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* prototype */
+static void object_bases_iterator_next(BLI_Iterator *iter, const int flag);
+
+
+/*********************** Layer Collections and bases *************************/
+
+static LayerCollection *layer_collection_add(ListBase *lb_parent, Collection *collection)
+{
+ LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base");
+ lc->collection = collection;
+ BLI_addtail(lb_parent, lc);
+
+ return lc;
+}
+
+static void layer_collection_free(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc == view_layer->active_collection) {
+ view_layer->active_collection = NULL;
+ }
+
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ layer_collection_free(view_layer, nlc);
+ }
+
+ BLI_freelistN(&lc->layer_collections);
+}
+
+static Base *object_base_new(Object *ob)
+{
+ Base *base = MEM_callocN(sizeof(Base), "Object Base");
+ base->object = ob;
+ return base;
+}
+
+/********************************* View Layer ********************************/
+
+
+/* RenderLayer */
+
+/* Returns the default view layer to view in workspaces if there is
+ * none linked to the workspace yet. */
+ViewLayer *BKE_view_layer_default_view(const Scene *scene)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (!(view_layer->flag & VIEW_LAYER_RENDER)) {
+ return view_layer;
+ }
+ }
+
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
+}
+
+/* Returns the default view layer to render if we need to render just one. */
+ViewLayer *BKE_view_layer_default_render(const Scene *scene)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (view_layer->flag & VIEW_LAYER_RENDER) {
+ return view_layer;
+ }
+ }
+
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
+}
+
+/* Returns view layer with matching name, or NULL if not found. */
+ViewLayer *BKE_view_layer_find(const Scene *scene, const char *layer_name)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (STREQ(view_layer->name, layer_name)) {
+ return view_layer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * This is a placeholder to know which areas of the code need to be addressed
+ * for the Workspace changes. Never use this, you should typically get the
+ * active layer from the context or window.
+ */
+ViewLayer *BKE_view_layer_context_active_PLACEHOLDER(const Scene *scene)
+{
+ BLI_assert(scene->view_layers.first);
+ return scene->view_layers.first;
+}
+
+static ViewLayer *view_layer_add(const char *name)
+{
+ if (!name) {
+ name = DATA_("View Layer");
+ }
+
+ ViewLayer *view_layer = MEM_callocN(sizeof(ViewLayer), "View Layer");
+ view_layer->flag = VIEW_LAYER_RENDER | VIEW_LAYER_FREESTYLE;
+
+ BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name));
+
+ /* Pure rendering pipeline settings. */
+ view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */
+ view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
+ view_layer->pass_alpha_threshold = 0.5f;
+ BKE_freestyle_config_init(&view_layer->freestyle_config);
+
+ return view_layer;
+}
+
+/**
+ * Add a new view layer
+ * by default, a view layer has the master collection
+ */
+ViewLayer *BKE_view_layer_add(Scene *scene, const char *name)
+{
+ ViewLayer *view_layer = view_layer_add(name);
+
+ BLI_addtail(&scene->view_layers, view_layer);
+
+ /* unique name */
+ BLI_uniquename(
+ &scene->view_layers, view_layer, DATA_("ViewLayer"), '.',
+ offsetof(ViewLayer, name), sizeof(view_layer->name));
+
+ BKE_layer_collection_sync(scene, view_layer);
+
+ return view_layer;
+}
+
+void BKE_view_layer_free(ViewLayer *view_layer)
+{
+ BKE_view_layer_free_ex(view_layer, true);
+}
+
+/**
+ * Free (or release) any data used by this ViewLayer.
+ */
+void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
+{
+ view_layer->basact = NULL;
+
+ BLI_freelistN(&view_layer->object_bases);
+
+ if (view_layer->object_bases_hash) {
+ BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
+ }
+
+ for (LayerCollection *lc = view_layer->layer_collections.first; lc; lc = lc->next) {
+ layer_collection_free(view_layer, lc);
+ }
+ BLI_freelistN(&view_layer->layer_collections);
+
+ for (ViewLayerEngineData *sled = view_layer->drawdata.first; sled; sled = sled->next) {
+ if (sled->storage) {
+ if (sled->free) {
+ sled->free(sled->storage);
+ }
+ MEM_freeN(sled->storage);
+ }
+ }
+ BLI_freelistN(&view_layer->drawdata);
+
+ MEM_SAFE_FREE(view_layer->stats);
+
+ BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user);
+
+ if (view_layer->id_properties) {
+ IDP_FreeProperty(view_layer->id_properties);
+ MEM_freeN(view_layer->id_properties);
+ }
+
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ MEM_freeN(view_layer);
+}
+
+/**
+ * Tag all the selected objects of a renderlayer
+ */
+void BKE_view_layer_selected_objects_tag(ViewLayer *view_layer, const int tag)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if ((base->flag & BASE_SELECTED) != 0) {
+ base->object->flag |= tag;
+ }
+ else {
+ base->object->flag &= ~tag;
+ }
+ }
+}
+
+static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc)
+{
+ for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) {
+ if (lcn == lc) {
+ return true;
+ }
+ if (find_scene_collection_in_scene_collections(&lcn->layer_collections, lc)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Fallback for when a Scene has no camera to use
+ *
+ * \param view_layer: in general you want to use the same ViewLayer that is used
+ * for depsgraph. If rendering you pass the scene active layer, when viewing in the viewport
+ * you want to get ViewLayer from context.
+ */
+Object *BKE_view_layer_camera_find(ViewLayer *view_layer)
+{
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object->type == OB_CAMERA) {
+ return base->object;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Find the ViewLayer a LayerCollection belongs to
+ */
+ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollection *lc)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (find_scene_collection_in_scene_collections(&view_layer->layer_collections, lc)) {
+ return view_layer;
+ }
+ }
+
+ return NULL;
+}
+
+/* Base */
+
+static void view_layer_bases_hash_create(ViewLayer *view_layer)
+{
+ static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER;
+
+ if (view_layer->object_bases_hash == NULL) {
+ BLI_mutex_lock(&hash_lock);
+
+ if (view_layer->object_bases_hash == NULL) {
+ view_layer->object_bases_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (base->object) {
+ BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
+ }
+ }
+ }
+
+ BLI_mutex_unlock(&hash_lock);
+ }
+}
+
+Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
+{
+ if (!view_layer->object_bases_hash) {
+ view_layer_bases_hash_create(view_layer);
+ }
+
+ return BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+}
+
+void BKE_view_layer_base_deselect_all(ViewLayer *view_layer)
+{
+ Base *base;
+
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag &= ~BASE_SELECTED;
+ }
+}
+
+void BKE_view_layer_base_select(Base *selbase)
+{
+ if ((selbase->flag & BASE_SELECTABLE) != 0) {
+ selbase->flag |= BASE_SELECTED;
+ }
+}
+
+void BKE_view_layer_base_select_and_set_active(struct ViewLayer *view_layer, Base *selbase)
+{
+ view_layer->basact = selbase;
+ BKE_view_layer_base_select(selbase);
+}
+
+/**************************** Copy View Layer and Layer Collections ***********************/
+
+static void layer_collections_copy_data(
+ ViewLayer *view_layer_dst, const ViewLayer *view_layer_src,
+ ListBase *layer_collections_dst, const ListBase *layer_collections_src)
+{
+ BLI_duplicatelist(layer_collections_dst, layer_collections_src);
+
+ LayerCollection *layer_collection_dst = layer_collections_dst->first;
+ const LayerCollection *layer_collection_src = layer_collections_src->first;
+
+ while (layer_collection_dst != NULL) {
+ layer_collections_copy_data(
+ view_layer_dst,
+ view_layer_src,
+ &layer_collection_dst->layer_collections,
+ &layer_collection_src->layer_collections);
+
+ if (layer_collection_src == view_layer_src->active_collection) {
+ view_layer_dst->active_collection = layer_collection_dst;
+ }
+
+ layer_collection_dst = layer_collection_dst->next;
+ layer_collection_src = layer_collection_src->next;
+ }
+}
+
+/**
+ * Only copy internal data of ViewLayer from source to already allocated/initialized destination.
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_view_layer_copy_data(
+ Scene *scene_dst, const Scene *UNUSED(scene_src),
+ ViewLayer *view_layer_dst, const ViewLayer *view_layer_src,
+ const int flag)
+{
+ if (view_layer_dst->id_properties != NULL) {
+ view_layer_dst->id_properties = IDP_CopyProperty_ex(view_layer_dst->id_properties, flag);
+ }
+ BKE_freestyle_config_copy(&view_layer_dst->freestyle_config, &view_layer_src->freestyle_config, flag);
+
+ view_layer_dst->stats = NULL;
+
+ /* Clear temporary data. */
+ BLI_listbase_clear(&view_layer_dst->drawdata);
+ view_layer_dst->object_bases_array = NULL;
+ view_layer_dst->object_bases_hash = NULL;
+
+ /* Copy layer collections and object bases. */
+ /* Inline 'BLI_duplicatelist' and update the active base. */
+ BLI_listbase_clear(&view_layer_dst->object_bases);
+ for (Base *base_src = view_layer_src->object_bases.first; base_src; base_src = base_src->next) {
+ Base *base_dst = MEM_dupallocN(base_src);
+ BLI_addtail(&view_layer_dst->object_bases, base_dst);
+ if (view_layer_src->basact == base_src) {
+ view_layer_dst->basact = base_dst;
+ }
+ }
+
+ view_layer_dst->active_collection = NULL;
+ layer_collections_copy_data(
+ view_layer_dst,
+ view_layer_src,
+ &view_layer_dst->layer_collections,
+ &view_layer_src->layer_collections);
+
+ LayerCollection *lc_scene_dst = view_layer_dst->layer_collections.first;
+ lc_scene_dst->collection = scene_dst->master_collection;
+}
+
+void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, const char *newname)
+{
+ char oldname[sizeof(view_layer->name)];
+
+ BLI_strncpy(oldname, view_layer->name, sizeof(view_layer->name));
+
+ BLI_strncpy_utf8(view_layer->name, newname, sizeof(view_layer->name));
+ BLI_uniquename(&scene->view_layers, view_layer, DATA_("ViewLayer"), '.', offsetof(ViewLayer, name), sizeof(view_layer->name));
+
+ if (scene->nodetree) {
+ bNode *node;
+ int index = BLI_findindex(&scene->view_layers, view_layer);
+
+ for (node = scene->nodetree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS && node->id == NULL) {
+ if (node->custom1 == index)
+ BLI_strncpy(node->name, view_layer->name, NODE_MAXSTR);
+ }
+ }
+ }
+
+ /* Fix all the animation data and windows which may link to this. */
+ BKE_animdata_fix_paths_rename_all(NULL, "view_layers", oldname, view_layer->name);
+
+ /* WM can be missing on startup. */
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win->scene == scene && STREQ(win->view_layer_name, oldname)) {
+ STRNCPY(win->view_layer_name, view_layer->name);
+ }
+ }
+ }
+
+ /* Dependency graph uses view layer name based lookups. */
+ DEG_id_tag_update(&scene->id, 0);
+}
+
+/* LayerCollection */
+
+/**
+ * Recursively get the collection for a given index
+ */
+static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i)
+{
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ if (*i == number) {
+ return lc;
+ }
+
+ (*i)++;
+ }
+
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i);
+ if (lc_nested) {
+ return lc_nested;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Get the collection for a given index
+ */
+LayerCollection *BKE_layer_collection_from_index(ViewLayer *view_layer, const int index)
+{
+ int i = 0;
+ return collection_from_index(&view_layer->layer_collections, index, &i);
+}
+
+/**
+ * Get the active collection
+ */
+LayerCollection *BKE_layer_collection_get_active(ViewLayer *view_layer)
+{
+ return view_layer->active_collection;
+}
+
+/*
+ * Activate collection
+ */
+bool BKE_layer_collection_activate(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ return false;
+ }
+
+ view_layer->active_collection = lc;
+ return true;
+}
+
+/**
+ * Activate first parent collection
+ */
+LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc)
+{
+ CollectionParent *parent = lc->collection->parents.first;
+
+ if (parent) {
+ lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection);
+ }
+ else {
+ lc = NULL;
+ }
+
+ if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ /* Don't activate excluded collections. */
+ return BKE_layer_collection_activate_parent(view_layer, lc);
+ }
+
+ if (!lc) {
+ lc = view_layer->layer_collections.first;
+ }
+
+ view_layer->active_collection = lc;
+ return lc;
+}
+
+/**
+ * Recursively get the count of collections
+ */
+static int collection_count(ListBase *lb)
+{
+ int i = 0;
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ i += collection_count(&lc->layer_collections) + 1;
+ }
+ return i;
+}
+
+/**
+ * Get the total number of collections
+ * (including all the nested collections)
+ */
+int BKE_layer_collection_count(ViewLayer *view_layer)
+{
+ return collection_count(&view_layer->layer_collections);
+}
+
+/**
+ * Recursively get the index for a given collection
+ */
+static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i)
+{
+ for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ if (lcol == lc) {
+ return *i;
+ }
+
+ (*i)++;
+ }
+
+ for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) {
+ int i_nested = index_from_collection(&lcol->layer_collections, lc, i);
+ if (i_nested != -1) {
+ return i_nested;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Return -1 if not found
+ */
+int BKE_layer_collection_findindex(ViewLayer *view_layer, const LayerCollection *lc)
+{
+ int i = 0;
+ return index_from_collection(&view_layer->layer_collections, lc, &i);
+}
+
+/*********************************** Syncing *********************************
+ *
+ * The layer collection tree mirrors the scene collection tree. Whenever that
+ * changes we need to synchronize them so that there is a corresponding layer
+ * collection for each collection. Note that the scene collection tree can
+ * contain link or override collections, and so this is also called on .blend
+ * file load to ensure any new or removed collections are synced.
+ *
+ * The view layer also contains a list of bases for each object that exists
+ * in at least one layer collection. That list is also synchronized here, and
+ * stores state like selection. */
+
+static short layer_collection_sync(
+ ViewLayer *view_layer, const ListBase *lb_scene,
+ ListBase *lb_layer, ListBase *new_object_bases,
+ short parent_exclude, short parent_restrict)
+{
+ /* TODO: support recovery after removal of intermediate collections, reordering, ..
+ * For local edits we can make editing operating do the appropriate thing, but for
+ * linking we can only sync after the fact. */
+
+ /* Remove layer collections that no longer have a corresponding scene collection. */
+ for (LayerCollection *lc = lb_layer->first; lc;) {
+ /* Note ID remap can set lc->collection to NULL when deleting collections. */
+ LayerCollection *lc_next = lc->next;
+ Collection *collection = (lc->collection) ?
+ BLI_findptr(lb_scene, lc->collection, offsetof(CollectionChild, collection)) : NULL;
+
+ if (!collection) {
+ if (lc == view_layer->active_collection) {
+ view_layer->active_collection = NULL;
+ }
+
+ /* Free recursively. */
+ layer_collection_free(view_layer, lc);
+ BLI_freelinkN(lb_layer, lc);
+ }
+
+ lc = lc_next;
+ }
+
+ /* Add layer collections for any new scene collections, and ensure order is the same. */
+ ListBase new_lb_layer = {NULL, NULL};
+ short runtime_flag = 0;
+
+ for (const CollectionChild *child = lb_scene->first; child; child = child->next) {
+ Collection *collection = child->collection;
+ LayerCollection *lc = BLI_findptr(lb_layer, collection, offsetof(LayerCollection, collection));
+
+ if (lc) {
+ BLI_remlink(lb_layer, lc);
+ BLI_addtail(&new_lb_layer, lc);
+ }
+ else {
+ lc = layer_collection_add(&new_lb_layer, collection);
+ lc->flag = parent_exclude;
+ }
+
+ /* Collection restrict is inherited. */
+ short child_restrict = parent_restrict;
+ if (!(collection->flag & COLLECTION_IS_MASTER)) {
+ child_restrict |= collection->flag;
+ }
+
+ /* Sync child collections. */
+ short child_runtime_flag = layer_collection_sync(
+ view_layer, &collection->children,
+ &lc->layer_collections, new_object_bases,
+ lc->flag, child_restrict);
+
+ /* Layer collection exclude is not inherited. */
+ if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
+ lc->runtime_flag = 0;
+ continue;
+ }
+ else {
+ lc->runtime_flag = child_runtime_flag;
+ }
+
+ /* Sync objects, except if collection was excluded. */
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ if (cob->ob == NULL) {
+ continue;
+ }
+
+ Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, cob->ob);
+
+ if (base) {
+ /* Move from old base list to new base list. Base might have already
+ * been moved to the new base list and the first/last test ensure that
+ * case also works. */
+ if (!ELEM(base, new_object_bases->first, new_object_bases->last)) {
+ BLI_remlink(&view_layer->object_bases, base);
+ BLI_addtail(new_object_bases, base);
+ }
+ }
+ else {
+ /* Create new base. */
+ base = object_base_new(cob->ob);
+ BLI_addtail(new_object_bases, base);
+ BLI_ghash_insert(view_layer->object_bases_hash, base->object, base);
+ }
+
+ int object_restrict = base->object->restrictflag;
+
+ if (((child_restrict & COLLECTION_RESTRICT_VIEW) == 0) &&
+ ((object_restrict & OB_RESTRICT_VIEW) == 0))
+ {
+ base->flag |= BASE_VISIBLE | BASE_ENABLED | BASE_ENABLED_VIEWPORT;
+
+ if (((child_restrict & COLLECTION_RESTRICT_SELECT) == 0) &&
+ ((object_restrict & OB_RESTRICT_SELECT) == 0))
+ {
+ base->flag |= BASE_SELECTABLE;
+ }
+ }
+
+ if (((child_restrict & COLLECTION_RESTRICT_RENDER) == 0) &&
+ ((object_restrict & OB_RESTRICT_RENDER) == 0))
+
+ {
+ base->flag |= BASE_ENABLED_RENDER;
+ }
+
+ /* Update runtime flags used for display and tools. */
+ if (base->flag & BASE_VISIBLE) {
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_ENABLED_OBJECTS;
+ }
+
+ if (base->flag & BASE_HIDDEN) {
+ view_layer->runtime_flag |= VIEW_LAYER_HAS_HIDE;
+ }
+ else if (base->flag & BASE_VISIBLE) {
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_VISIBLE_OBJECTS;
+ }
+
+ /* Holdout and indirect only */
+ if (lc->flag & LAYER_COLLECTION_HOLDOUT) {
+ base->flag |= BASE_HOLDOUT;
+ }
+ if (lc->flag & LAYER_COLLECTION_INDIRECT_ONLY) {
+ base->flag |= BASE_INDIRECT_ONLY;
+ }
+
+ lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS;
+ }
+
+ runtime_flag |= lc->runtime_flag;
+ }
+
+ /* Replace layer collection list with new one. */
+ *lb_layer = new_lb_layer;
+ BLI_assert(BLI_listbase_count(lb_scene) == BLI_listbase_count(lb_layer));
+
+ return runtime_flag;
+}
+
+/**
+ * Update view layer collection tree from collections used in the scene.
+ * This is used when collections are removed or added, both while editing
+ * and on file loaded in case linked data changed or went missing.
+ */
+void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
+{
+ if (!scene->master_collection) {
+ /* Happens for old files that don't have versioning applied yet. */
+ return;
+ }
+
+ /* Free cache. */
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ /* Create object to base hash if it does not exist yet. */
+ if (!view_layer->object_bases_hash) {
+ view_layer_bases_hash_create(view_layer);
+ }
+
+ /* Clear visible and selectable flags to be reset. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag &= ~(BASE_VISIBLE |
+ BASE_ENABLED |
+ BASE_SELECTABLE |
+ BASE_ENABLED_VIEWPORT |
+ BASE_ENABLED_RENDER |
+ BASE_HOLDOUT |
+ BASE_INDIRECT_ONLY);
+ }
+
+ view_layer->runtime_flag = 0;
+
+ /* Generate new layer connections and object bases when collections changed. */
+ CollectionChild child = {NULL, NULL, scene->master_collection};
+ const ListBase collections = {&child, &child};
+ ListBase new_object_bases = {NULL, NULL};
+
+ const short parent_exclude = 0, parent_restrict = 0;
+ layer_collection_sync(
+ view_layer, &collections,
+ &view_layer->layer_collections, &new_object_bases,
+ parent_exclude, parent_restrict);
+
+ /* Any remaning object bases are to be removed. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (view_layer->basact == base) {
+ view_layer->basact = NULL;
+ }
+
+ if (base->object) {
+ BLI_ghash_remove(view_layer->object_bases_hash, base->object, NULL, NULL);
+ }
+ }
+
+ BLI_freelistN(&view_layer->object_bases);
+ view_layer->object_bases = new_object_bases;
+
+ /* Always set a valid active collection. */
+ LayerCollection *active = view_layer->active_collection;
+
+ if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) {
+ BKE_layer_collection_activate_parent(view_layer, active);
+ }
+ else if (active == NULL) {
+ view_layer->active_collection = view_layer->layer_collections.first;
+ }
+}
+
+void BKE_scene_collection_sync(const Scene *scene)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ BKE_layer_collection_sync(scene, view_layer);
+ }
+}
+
+void BKE_main_collection_sync(const Main *bmain)
+{
+ /* TODO: if a single collection changed, figure out which
+ * scenes it belongs to and only update those. */
+
+ /* TODO: optimize for file load so only linked collections get checked? */
+
+ for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ BKE_scene_collection_sync(scene);
+ }
+}
+
+void BKE_main_collection_sync_remap(const Main *bmain)
+{
+ /* On remapping of object or collection pointers free caches. */
+ /* TODO: try to make this faster */
+
+ for (const Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+
+ if (view_layer->object_bases_hash) {
+ BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
+ view_layer->object_bases_hash = NULL;
+ }
+ }
+ }
+
+ for (Collection *collection = bmain->collection.first; collection; collection = collection->id.next) {
+ BKE_collection_object_cache_free(collection);
+ DEG_id_tag_update_ex((Main *)bmain, &collection->id, DEG_TAG_COPY_ON_WRITE);
+ }
+
+ BKE_main_collection_sync(bmain);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/**
+ * Select all the objects of this layer collection
+ *
+ * It also select the objects that are in nested collections.
+ * \note Recursive
+ */
+bool BKE_layer_collection_objects_select(ViewLayer *view_layer, LayerCollection *lc, bool deselect)
+{
+ if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
+
+ bool changed = false;
+
+ if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+
+ if (base) {
+ if (deselect) {
+ if (base->flag & BASE_SELECTED) {
+ base->flag &= ~BASE_SELECTED;
+ changed = true;
+ }
+ }
+ else {
+ if ((base->flag & BASE_SELECTABLE) && !(base->flag & BASE_SELECTED)) {
+ base->flag |= BASE_SELECTED;
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ changed |= BKE_layer_collection_objects_select(view_layer, iter, deselect);
+ }
+
+ return changed;
+}
+
+bool BKE_layer_collection_has_selected_objects(ViewLayer *view_layer, LayerCollection *lc)
+{
+ if (lc->collection->flag & COLLECTION_RESTRICT_SELECT) {
+ return false;
+ }
+
+ if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
+ for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, cob->ob);
+
+ if (base && (base->flag & BASE_SELECTED)) {
+ return true;
+ }
+ }
+ }
+
+ for (LayerCollection *iter = lc->layer_collections.first; iter; iter = iter->next) {
+ if (BKE_layer_collection_has_selected_objects(view_layer, iter)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* Update after toggling visibility of an object base. */
+void BKE_base_set_visible(Scene *scene, ViewLayer *view_layer, Base *base, bool extend)
+{
+ if (!extend) {
+ /* Make only one base visible. */
+ for (Base *other = view_layer->object_bases.first; other; other = other->next) {
+ other->flag |= BASE_HIDDEN;
+ }
+
+ base->flag &= ~BASE_HIDDEN;
+ }
+ else {
+ /* Toggle visibility of one base. */
+ base->flag ^= BASE_HIDDEN;
+ }
+
+ BKE_layer_collection_sync(scene, view_layer);
+}
+
+void BKE_layer_collection_set_visible(Scene *scene, ViewLayer *view_layer, LayerCollection *lc, bool extend)
+{
+ if (!extend) {
+ /* Make only objects from one collection visible. */
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->flag |= BASE_HIDDEN;
+ }
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(lc->collection, ob)
+ {
+ Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+
+ if (base) {
+ base->flag &= ~BASE_HIDDEN;
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ BKE_layer_collection_activate(view_layer, lc);
+ }
+ else {
+ /* Toggle visibility of objects from collection. */
+ bool hide = (lc->runtime_flag & LAYER_COLLECTION_HAS_VISIBLE_OBJECTS) != 0;
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(lc->collection, ob)
+ {
+ Base *base = BLI_ghash_lookup(view_layer->object_bases_hash, ob);
+
+ if (base) {
+ if (hide) {
+ base->flag |= BASE_HIDDEN;
+ }
+ else {
+ base->flag &= ~BASE_HIDDEN;
+ }
+ }
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+ }
+
+ BKE_layer_collection_sync(scene, view_layer);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const Collection *collection)
+{
+ if (lc->collection == collection) {
+ return lc;
+ }
+
+ for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
+ LayerCollection *found = find_layer_collection_by_scene_collection(nlc, collection);
+ if (found) {
+ return found;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Return the first matching LayerCollection in the ViewLayer for the Collection.
+ */
+LayerCollection *BKE_layer_collection_first_from_scene_collection(ViewLayer *view_layer, const Collection *collection)
+{
+ for (LayerCollection *layer_collection = view_layer->layer_collections.first;
+ layer_collection != NULL;
+ layer_collection = layer_collection->next)
+ {
+ LayerCollection *found = find_layer_collection_by_scene_collection(layer_collection, collection);
+
+ if (found != NULL) {
+ return found;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * See if view layer has the scene collection linked directly, or indirectly (nested)
+ */
+bool BKE_view_layer_has_collection(ViewLayer *view_layer, const Collection *collection)
+{
+ return BKE_layer_collection_first_from_scene_collection(view_layer, collection) != NULL;
+}
+
+/**
+ * See if the object is in any of the scene layers of the scene
+ */
+bool BKE_scene_has_object(Scene *scene, Object *ob)
+{
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Override */
+
+/**
+ * Add a new datablock override
+ */
+void BKE_override_view_layer_datablock_add(
+ ViewLayer *view_layer, int id_type, const char *data_path, const ID *owner_id)
+{
+ UNUSED_VARS(view_layer, id_type, data_path, owner_id);
+ TODO_LAYER_OVERRIDE;
+}
+
+/**
+ * Add a new int override
+ */
+void BKE_override_view_layer_int_add(
+ ViewLayer *view_layer, int id_type, const char *data_path, const int value)
+{
+ UNUSED_VARS(view_layer, id_type, data_path, value);
+ TODO_LAYER_OVERRIDE;
+}
+
+/**
+ * Add a new boolean override
+ */
+void BKE_override_layer_collection_boolean_add(
+ struct LayerCollection *layer_collection, int id_type, const char *data_path, const bool value)
+{
+ UNUSED_VARS(layer_collection, id_type, data_path, value);
+ TODO_LAYER_OVERRIDE;
+}
+
+/** \} */
+
+/* Iterators */
+
+/* -------------------------------------------------------------------- */
+/** \name Private Iterator Helpers
+ * \{ */
+
+static void object_bases_iterator_begin(BLI_Iterator *iter, void *data_in, const int flag)
+{
+ ViewLayer *view_layer = data_in;
+ Base *base = view_layer->object_bases.first;
+
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->valid = false;
+ return;
+ }
+
+ 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->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;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_selected_objects_iterator
+ * See: #FOREACH_SELECTED_OBJECT_BEGIN
+ * \{ */
+
+void BKE_view_layer_selected_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_objects_iterator_next(BLI_Iterator *iter)
+{
+ objects_iterator_next(iter, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_visible_objects_iterator
+ * \{ */
+
+void BKE_view_layer_visible_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_VISIBLE);
+}
+
+void BKE_view_layer_visible_objects_iterator_next(BLI_Iterator *iter)
+{
+ objects_iterator_next(iter, BASE_VISIBLE);
+}
+
+void BKE_view_layer_visible_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_selected_editable_objects_iterator
+ * \{ */
+
+void BKE_view_layer_selected_editable_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ objects_iterator_begin(iter, data_in, BASE_SELECTED);
+ if (iter->valid) {
+ if (BKE_object_is_libdata((Object *)iter->current) == false) {
+ // First object is valid (selectable and not libdata) -> all good.
+ return;
+ }
+ else {
+ // Object is selectable but not editable -> search for another one.
+ BKE_view_layer_selected_editable_objects_iterator_next(iter);
+ }
+ }
+}
+
+void BKE_view_layer_selected_editable_objects_iterator_next(BLI_Iterator *iter)
+{
+ // Search while there are objects and the one we have is not editable (editable = not libdata).
+ do {
+ objects_iterator_next(iter, BASE_SELECTED);
+ } while (iter->valid && BKE_object_is_libdata((Object *)iter->current) != false);
+}
+
+void BKE_view_layer_selected_editable_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_selected_bases_iterator
+ * \{ */
+
+void BKE_view_layer_selected_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ object_bases_iterator_begin(iter, data_in, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_bases_iterator_next(BLI_Iterator *iter)
+{
+ object_bases_iterator_next(iter, BASE_SELECTED);
+}
+
+void BKE_view_layer_selected_bases_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_visible_bases_iterator
+ * \{ */
+
+void BKE_view_layer_visible_bases_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ object_bases_iterator_begin(iter, data_in, BASE_VISIBLE);
+}
+
+void BKE_view_layer_visible_bases_iterator_next(BLI_Iterator *iter)
+{
+ object_bases_iterator_next(iter, BASE_VISIBLE);
+}
+
+void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_renderable_objects_iterator
+ * \{ */
+
+void BKE_view_layer_renderable_objects_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ struct ObjectsRenderableIteratorData *data = data_in;
+
+ /* Tag objects to prevent going over the same object twice. */
+ for (Scene *scene = data->scene; scene; scene = scene->set) {
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ base->object->id.flag |= LIB_TAG_DOIT;
+ }
+ }
+ }
+
+ ViewLayer *view_layer = data->scene->view_layers.first;
+ data->iter.view_layer = view_layer;
+
+ data->base_temp.next = view_layer->object_bases.first;
+ data->iter.base = &data->base_temp;
+
+ data->iter.set = NULL;
+
+ iter->data = data_in;
+ BKE_view_layer_renderable_objects_iterator_next(iter);
+}
+
+void BKE_view_layer_renderable_objects_iterator_next(BLI_Iterator *iter)
+{
+ /* Set it early in case we need to exit and we are running from within a loop. */
+ iter->skip = true;
+
+ struct ObjectsRenderableIteratorData *data = iter->data;
+ Base *base = data->iter.base->next;
+
+ /* There is still a base in the current scene layer. */
+ if (base != NULL) {
+ Object *ob = base->object;
+
+ /* We need to set the iter.base even if the rest fail otherwise
+ * we keep checking the exactly same base over and over again. */
+ data->iter.base = base;
+
+ if (ob->id.flag & LIB_TAG_DOIT) {
+ ob->id.flag &= ~LIB_TAG_DOIT;
+
+ if ((base->flag & BASE_VISIBLE) != 0) {
+ iter->skip = false;
+ iter->current = ob;
+ }
+ }
+ return;
+ }
+
+ /* Time to go to the next scene layer. */
+ if (data->iter.set == NULL) {
+ while ((data->iter.view_layer = data->iter.view_layer->next)) {
+ ViewLayer *view_layer = data->iter.view_layer;
+ if (view_layer->flag & VIEW_LAYER_RENDER) {
+ data->base_temp.next = view_layer->object_bases.first;
+ data->iter.base = &data->base_temp;
+ return;
+ }
+ }
+
+ /* Setup the "set" for the next iteration. */
+ data->scene_temp.set = data->scene;
+ data->iter.set = &data->scene_temp;
+ return;
+ }
+
+ /* Look for an object in the next set. */
+ while ((data->iter.set = data->iter.set->set)) {
+ ViewLayer *view_layer = BKE_view_layer_default_render(data->iter.set);
+ data->base_temp.next = view_layer->object_bases.first;
+ data->iter.base = &data->base_temp;
+ return;
+ }
+
+ iter->valid = false;
+}
+
+void BKE_view_layer_renderable_objects_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* Do nothing - iter->data was static allocated, we can't free it. */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BKE_view_layer_bases_in_mode_iterator
+ * \{ */
+
+void BKE_view_layer_bases_in_mode_iterator_begin(BLI_Iterator *iter, void *data_in)
+{
+ struct ObjectsInModeIteratorData *data = data_in;
+ Base *base = data->base_active;
+
+ /* when there are no objects */
+ if (base == NULL) {
+ iter->valid = false;
+ return;
+ }
+ iter->data = data_in;
+ iter->current = base;
+}
+
+void BKE_view_layer_bases_in_mode_iterator_next(BLI_Iterator *iter)
+{
+ struct ObjectsInModeIteratorData *data = iter->data;
+ Base *base = iter->current;
+
+ if (base == data->base_active) {
+ /* first step */
+ base = data->view_layer->object_bases.first;
+ if (base == data->base_active) {
+ base = base->next;
+ }
+ }
+ else {
+ base = base->next;
+ }
+
+ while (base) {
+ if ((base->object->type == data->base_active->object->type) &&
+ (base != data->base_active) &&
+ (base->object->mode & data->object_mode))
+ {
+ iter->current = base;
+ return;
+ }
+ base = base->next;
+ }
+ iter->valid = false;
+}
+
+void BKE_view_layer_bases_in_mode_iterator_end(BLI_Iterator *UNUSED(iter))
+{
+ /* do nothing */
+}
+
+/** \} */
+
+/* Evaluation */
+
+void BKE_layer_eval_view_layer(
+ struct Depsgraph *depsgraph,
+ struct Scene *UNUSED(scene),
+ ViewLayer *view_layer)
+{
+ DEG_debug_print_eval(depsgraph, __func__, view_layer->name, view_layer);
+
+ /* Visibility based on depsgraph mode. */
+ const eEvaluationMode mode = DEG_get_mode(depsgraph);
+ const int base_flag = (mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER;
+
+ /* Create array of bases, for fast index-based lookup. */
+ const int num_object_bases = BLI_listbase_count(&view_layer->object_bases);
+ MEM_SAFE_FREE(view_layer->object_bases_array);
+ view_layer->object_bases_array = MEM_malloc_arrayN(
+ num_object_bases, sizeof(Base *), "view_layer->object_bases_array");
+ int base_index = 0;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ /* Compute visibility for depsgraph evaluation mode. */
+ if (base->flag & base_flag) {
+ base->flag |= BASE_ENABLED | BASE_VISIBLE;
+
+ if (mode == DAG_EVAL_VIEWPORT && (base->flag & BASE_HIDDEN)) {
+ base->flag &= ~BASE_VISIBLE;
+ }
+ }
+ else {
+ base->flag &= ~(BASE_ENABLED | BASE_VISIBLE | BASE_SELECTABLE);
+ }
+
+ /* If base is not selectabled, clear select. */
+ if ((base->flag & BASE_SELECTABLE) == 0) {
+ base->flag &= ~BASE_SELECTED;
+ }
+
+ view_layer->object_bases_array[base_index++] = base;
+ }
+
+ /* Flush back base flag to the original view layer for editing. */
+ if (view_layer == DEG_get_evaluated_view_layer(depsgraph)) {
+ ViewLayer *view_layer_orig = DEG_get_input_view_layer(depsgraph);
+ Base *base_orig = view_layer_orig->object_bases.first;
+ const Base *base_eval = view_layer->object_bases.first;
+ while (base_orig != NULL) {
+ base_orig->flag = base_eval->flag;
+ base_orig = base_orig->next;
+ base_eval = base_eval->next;
+ }
+ }
+}
+
+void BKE_layer_eval_view_layer_indexed(
+ struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ int view_layer_index)
+{
+ BLI_assert(view_layer_index >= 0);
+ ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
+ BLI_assert(view_layer != NULL);
+ BKE_layer_eval_view_layer(depsgraph, scene, view_layer);
+}
diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c
new file mode 100644
index 00000000000..94bac8a33d6
--- /dev/null
+++ b/source/blender/blenkernel/intern/layer_utils.c
@@ -0,0 +1,125 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/layer_utils.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "BLI_array.h"
+#include "BLI_listbase.h"
+
+#include "BKE_collection.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+
+#include "DNA_ID.h"
+#include "DNA_layer_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+Base **BKE_view_layer_array_from_bases_in_mode_params(
+ ViewLayer *view_layer, uint *r_len,
+ const struct ObjectsInModeParams *params)
+{
+ if (params->no_dup_data) {
+ FOREACH_BASE_IN_MODE_BEGIN(view_layer, params->object_mode, base_iter) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ id->tag |= LIB_TAG_DOIT;
+ }
+ } FOREACH_BASE_IN_MODE_END;
+ }
+
+ Base **base_array = NULL;
+ BLI_array_declare(base_array);
+
+ FOREACH_BASE_IN_MODE_BEGIN(view_layer, params->object_mode, base_iter) {
+ if (params->filter_fn) {
+ if (!params->filter_fn(base_iter->object, params->filter_userdata)) {
+ continue;
+ }
+ }
+ if (params->no_dup_data) {
+ ID *id = base_iter->object->data;
+ if (id) {
+ if (id->tag & LIB_TAG_DOIT) {
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+ BLI_array_append(base_array, base_iter);
+ } FOREACH_BASE_IN_MODE_END;
+
+ if (base_array != NULL) {
+ base_array = MEM_reallocN(base_array, sizeof(*base_array) * BLI_array_len(base_array));
+ }
+ *r_len = BLI_array_len(base_array);
+ return base_array;
+}
+
+Object **BKE_view_layer_array_from_objects_in_mode_params(
+ ViewLayer *view_layer, uint *r_len,
+ const struct ObjectsInModeParams *params)
+{
+ Base **base_array = BKE_view_layer_array_from_bases_in_mode_params(
+ view_layer, r_len, params);
+ if (base_array != NULL) {
+ for (uint i = 0; i < *r_len; i++) {
+ ((Object **)base_array)[i] = base_array[i]->object;
+ }
+ }
+ return (Object **)base_array;
+}
+
+bool BKE_view_layer_filter_edit_mesh_has_uvs(Object *ob, void *UNUSED(user_data))
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em != NULL) {
+ if (CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV) != -1) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool BKE_view_layer_filter_edit_mesh_has_edges(Object *ob, void *UNUSED(user_data))
+{
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+ if (em != NULL) {
+ if (em->bm->totedge != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index a6cee54d81f..aa6cbcc343e 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -47,7 +47,7 @@
#include "DNA_brush_types.h"
#include "DNA_cachefile_types.h"
#include "DNA_camera_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
@@ -62,6 +62,7 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -70,6 +71,7 @@
#include "DNA_vfont_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_world_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -78,8 +80,8 @@
#include "BLI_memarena.h"
#include "BLI_mempool.h"
#include "BLI_string_utils.h"
-
#include "BLI_threads.h"
+
#include "BLT_translation.h"
#include "BKE_action.h"
@@ -89,12 +91,11 @@
#include "BKE_brush.h"
#include "BKE_camera.h"
#include "BKE_cachefile.h"
+#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_font.h"
#include "BKE_global.h"
-#include "BKE_group.h"
#include "BKE_gpencil.h"
#include "BKE_idcode.h"
#include "BKE_idprop.h"
@@ -103,6 +104,7 @@
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -117,6 +119,7 @@
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
+#include "BKE_lightprobe.h"
#include "BKE_sound.h"
#include "BKE_speaker.h"
#include "BKE_scene.h"
@@ -418,6 +421,9 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
case ID_SPK:
if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local);
return true;
+ case ID_LP:
+ if (!test) BKE_lightprobe_make_local(bmain, (LightProbe *)id, lib_local);
+ return true;
case ID_WO:
if (!test) BKE_world_make_local(bmain, (World *)id, lib_local);
return true;
@@ -431,7 +437,7 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local);
return true;
case ID_GR:
- if (!test) BKE_group_make_local(bmain, (Group *)id, lib_local);
+ if (!test) BKE_collection_make_local(bmain, (Collection *)id, lib_local);
return true;
case ID_AR:
if (!test) BKE_armature_make_local(bmain, (bArmature *)id, lib_local);
@@ -469,7 +475,11 @@ bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
case ID_CF:
if (!test) BKE_cachefile_make_local(bmain, (CacheFile *)id, lib_local);
return true;
+ case ID_WS:
case ID_SCR:
+ /* A bit special: can be appended but not linked. Return false
+ * since supporting make-local doesn't make much sense. */
+ return false;
case ID_LI:
case ID_KE:
case ID_WM:
@@ -589,6 +599,9 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
case ID_SPK:
BKE_speaker_copy_data(bmain, (Speaker *)*r_newid, (Speaker *)id, flag);
break;
+ case ID_LP:
+ BKE_lightprobe_copy_data(bmain, (LightProbe *)*r_newid, (LightProbe *)id, flag);
+ break;
case ID_CA:
BKE_camera_copy_data(bmain, (Camera *)*r_newid, (Camera *)id, flag);
break;
@@ -602,7 +615,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
BKE_text_copy_data(bmain, (Text *)*r_newid, (Text *)id, flag);
break;
case ID_GR:
- BKE_group_copy_data(bmain, (Group *)*r_newid, (Group *)id, flag);
+ BKE_collection_copy_data(bmain, (Collection *)*r_newid, (Collection *)id, flag);
break;
case ID_AR:
BKE_armature_copy_data(bmain, (bArmature *)*r_newid, (bArmature *)id, flag);
@@ -620,7 +633,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
BKE_particlesettings_copy_data(bmain, (ParticleSettings *)*r_newid, (ParticleSettings *)id, flag);
break;
case ID_GD:
- BKE_gpencil_copy_data(bmain, (bGPdata *)*r_newid, (bGPdata *)id, flag);
+ BKE_gpencil_copy_data((bGPdata *)*r_newid, (bGPdata *)id, flag);
break;
case ID_MC:
BKE_movieclip_copy_data(bmain, (MovieClip *)*r_newid, (MovieClip *)id, flag);
@@ -649,6 +662,7 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
case ID_LI:
case ID_SCR:
case ID_WM:
+ case ID_WS:
case ID_IP:
BLI_assert(0); /* Should have been rejected at start of function! */
break;
@@ -677,7 +691,76 @@ bool BKE_id_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag, con
*/
bool id_copy(Main *bmain, const ID *id, ID **newid, bool test)
{
- return BKE_id_copy_ex(bmain, id, newid, 0, test);
+ return BKE_id_copy_ex(bmain, id, newid, LIB_ID_COPY_SHAPEKEY, test);
+}
+
+/** Does a mere memory swap over the whole IDs data (including type-specific memory).
+ * \note Most internal ID data itself is not swapped (only IDProperties are). */
+void BKE_id_swap(Main *bmain, ID *id_a, ID *id_b)
+{
+ BLI_assert(GS(id_a->name) == GS(id_b->name));
+
+ const ID id_a_back = *id_a;
+ const ID id_b_back = *id_b;
+
+#define CASE_SWAP(_gs, _type) \
+ case _gs: \
+ SWAP(_type, *(_type *)id_a, *(_type *)id_b); \
+ break
+
+ switch ((ID_Type)GS(id_a->name)) {
+ CASE_SWAP(ID_SCE, Scene);
+ CASE_SWAP(ID_LI, Library);
+ CASE_SWAP(ID_OB, Object);
+ CASE_SWAP(ID_ME, Mesh);
+ CASE_SWAP(ID_CU, Curve);
+ CASE_SWAP(ID_MB, MetaBall);
+ CASE_SWAP(ID_MA, Material);
+ CASE_SWAP(ID_TE, Tex);
+ CASE_SWAP(ID_IM, Image);
+ CASE_SWAP(ID_LT, Lattice);
+ CASE_SWAP(ID_LA, Lamp);
+ CASE_SWAP(ID_LP, LightProbe);
+ CASE_SWAP(ID_CA, Camera);
+ CASE_SWAP(ID_KE, Key);
+ CASE_SWAP(ID_WO, World);
+ CASE_SWAP(ID_SCR, bScreen);
+ CASE_SWAP(ID_VF, VFont);
+ CASE_SWAP(ID_TXT, Text);
+ CASE_SWAP(ID_SPK, Speaker);
+ CASE_SWAP(ID_SO, bSound);
+ CASE_SWAP(ID_GR, Collection);
+ CASE_SWAP(ID_AR, bArmature);
+ CASE_SWAP(ID_AC, bAction);
+ CASE_SWAP(ID_NT, bNodeTree);
+ CASE_SWAP(ID_BR, Brush);
+ CASE_SWAP(ID_PA, ParticleSettings);
+ CASE_SWAP(ID_WM, wmWindowManager);
+ CASE_SWAP(ID_WS, WorkSpace);
+ CASE_SWAP(ID_GD, bGPdata);
+ CASE_SWAP(ID_MC, MovieClip);
+ CASE_SWAP(ID_MSK, Mask);
+ CASE_SWAP(ID_LS, FreestyleLineStyle);
+ CASE_SWAP(ID_PAL, Palette);
+ CASE_SWAP(ID_PC, PaintCurve);
+ CASE_SWAP(ID_CF, CacheFile);
+ case ID_IP:
+ break; /* Deprecated. */
+ }
+
+#undef CASE_SWAP
+
+ /* Restore original ID's internal data. */
+ *id_a = id_a_back;
+ *id_b = id_b_back;
+
+ /* Exception: IDProperties. */
+ id_a->properties = id_b_back.properties;
+ id_b->properties = id_a_back.properties;
+
+ /* Swap will have broken internal references to itself, restore them. */
+ BKE_libblock_relink_ex(bmain, id_a, id_b, id_a, false);
+ BKE_libblock_relink_ex(bmain, id_b, id_a, id_b, false);
}
/** Does *not* set ID->newid pointer. */
@@ -693,15 +776,23 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
if (id_copy(bmain, id, &newid, false) && newid) {
/* copy animation actions too */
BKE_animdata_copy_id_action(bmain, id, false);
- /* us is 1 by convention, but RNA_property_pointer_set
- * will also increment it, so set it to zero */
- newid->us = 0;
+ /* us is 1 by convention with new IDs, but RNA_property_pointer_set
+ * will also increment it, decrement it here. */
+ id_us_min(newid);
/* assign copy */
RNA_id_pointer_create(newid, &idptr);
RNA_property_pointer_set(ptr, prop, idptr);
RNA_property_update(C, ptr, prop);
+ /* tag grease pencil datablock and disable onion */
+ if (GS(id->name) == ID_GD) {
+ DEG_id_tag_update(id, OB_RECALC_OB | OB_RECALC_DATA);
+ DEG_id_tag_update(newid, OB_RECALC_OB | OB_RECALC_DATA);
+ bGPdata *gpd = (bGPdata *)newid;
+ gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS;
+ }
+
return true;
}
}
@@ -807,81 +898,6 @@ void BKE_libblock_management_usercounts_clear(Main *bmain, void *idv)
id->tag |= LIB_TAG_NO_USER_REFCOUNT;
}
-ListBase *which_libbase(Main *mainlib, short type)
-{
- switch ((ID_Type)type) {
- case ID_SCE:
- return &(mainlib->scene);
- case ID_LI:
- return &(mainlib->library);
- case ID_OB:
- return &(mainlib->object);
- case ID_ME:
- return &(mainlib->mesh);
- case ID_CU:
- return &(mainlib->curve);
- case ID_MB:
- return &(mainlib->mball);
- case ID_MA:
- return &(mainlib->mat);
- case ID_TE:
- return &(mainlib->tex);
- case ID_IM:
- return &(mainlib->image);
- case ID_LT:
- return &(mainlib->latt);
- case ID_LA:
- return &(mainlib->lamp);
- case ID_CA:
- return &(mainlib->camera);
- case ID_IP:
- return &(mainlib->ipo);
- case ID_KE:
- return &(mainlib->key);
- case ID_WO:
- return &(mainlib->world);
- case ID_SCR:
- return &(mainlib->screen);
- case ID_VF:
- return &(mainlib->vfont);
- case ID_TXT:
- return &(mainlib->text);
- case ID_SPK:
- return &(mainlib->speaker);
- case ID_SO:
- return &(mainlib->sound);
- case ID_GR:
- return &(mainlib->group);
- case ID_AR:
- return &(mainlib->armature);
- case ID_AC:
- return &(mainlib->action);
- case ID_NT:
- return &(mainlib->nodetree);
- case ID_BR:
- return &(mainlib->brush);
- case ID_PA:
- return &(mainlib->particle);
- case ID_WM:
- return &(mainlib->wm);
- case ID_GD:
- return &(mainlib->gpencil);
- case ID_MC:
- return &(mainlib->movieclip);
- case ID_MSK:
- return &(mainlib->mask);
- case ID_LS:
- return &(mainlib->linestyle);
- case ID_PAL:
- return &(mainlib->palettes);
- case ID_PC:
- return &(mainlib->paintcurves);
- case ID_CF:
- return &(mainlib->cachefiles);
- }
- return NULL;
-}
-
/**
* Clear or set given tags for all ids in listbase (runtime tags).
*/
@@ -963,72 +979,11 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
/* flag for full recalc */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ID_IS_LINKED(ob)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
}
- DAG_id_type_tag(bmain, ID_OB);
-}
-
-/**
- * puts into array *lb pointers to all the ListBase structs in main,
- * and returns the number of them as the function result. This is useful for
- * generic traversal of all the blocks in a Main (by traversing all the
- * lists in turn), without worrying about block types.
- *
- * \note MAX_LIBARRAY define should match this code */
-int set_listbasepointers(Main *main, ListBase **lb)
-{
- /* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
- * This is important because freeing data decreases usercounts of other datablocks,
- * if this data is its self freed it can crash. */
- lb[INDEX_ID_LI] = &(main->library); /* Libraries may be accessed from pretty much any other ID... */
- lb[INDEX_ID_IP] = &(main->ipo);
- lb[INDEX_ID_AC] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */
- lb[INDEX_ID_KE] = &(main->key);
- lb[INDEX_ID_GD] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
- lb[INDEX_ID_NT] = &(main->nodetree);
- lb[INDEX_ID_IM] = &(main->image);
- lb[INDEX_ID_TE] = &(main->tex);
- lb[INDEX_ID_MA] = &(main->mat);
- lb[INDEX_ID_VF] = &(main->vfont);
-
- /* Important!: When adding a new object type,
- * the specific data should be inserted here
- */
-
- lb[INDEX_ID_AR] = &(main->armature);
-
- lb[INDEX_ID_CF] = &(main->cachefiles);
- lb[INDEX_ID_ME] = &(main->mesh);
- lb[INDEX_ID_CU] = &(main->curve);
- lb[INDEX_ID_MB] = &(main->mball);
-
- lb[INDEX_ID_LT] = &(main->latt);
- lb[INDEX_ID_LA] = &(main->lamp);
- lb[INDEX_ID_CA] = &(main->camera);
-
- lb[INDEX_ID_TXT] = &(main->text);
- lb[INDEX_ID_SO] = &(main->sound);
- lb[INDEX_ID_GR] = &(main->group);
- lb[INDEX_ID_PAL] = &(main->palettes);
- lb[INDEX_ID_PC] = &(main->paintcurves);
- lb[INDEX_ID_BR] = &(main->brush);
- lb[INDEX_ID_PA] = &(main->particle);
- lb[INDEX_ID_SPK] = &(main->speaker);
-
- lb[INDEX_ID_WO] = &(main->world);
- lb[INDEX_ID_MC] = &(main->movieclip);
- lb[INDEX_ID_SCR] = &(main->screen);
- lb[INDEX_ID_OB] = &(main->object);
- lb[INDEX_ID_LS] = &(main->linestyle); /* referenced by scenes */
- lb[INDEX_ID_SCE] = &(main->scene);
- lb[INDEX_ID_WM] = &(main->wm);
- lb[INDEX_ID_MSK] = &(main->mask);
-
- lb[INDEX_ID_NULL] = NULL;
-
- return (MAX_LIBARRAY - 1);
+ DEG_id_type_tag(bmain, ID_OB);
}
/* *********** ALLOC AND FREE *****************
@@ -1075,8 +1030,9 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
CASE_RETURN(ID_VF, VFont);
CASE_RETURN(ID_TXT, Text);
CASE_RETURN(ID_SPK, Speaker);
+ CASE_RETURN(ID_LP, LightProbe);
CASE_RETURN(ID_SO, bSound);
- CASE_RETURN(ID_GR, Group);
+ CASE_RETURN(ID_GR, Collection);
CASE_RETURN(ID_AR, bArmature);
CASE_RETURN(ID_AC, bAction);
CASE_RETURN(ID_NT, bNodeTree);
@@ -1090,6 +1046,7 @@ size_t BKE_libblock_get_alloc_info(short type, const char **name)
CASE_RETURN(ID_PAL, Palette);
CASE_RETURN(ID_PC, PaintCurve);
CASE_RETURN(ID_CF, CacheFile);
+ CASE_RETURN(ID_WS, WorkSpace);
}
return 0;
#undef CASE_RETURN
@@ -1147,7 +1104,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
/* TODO to be removed from here! */
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0) {
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
}
}
else {
@@ -1206,6 +1163,9 @@ void BKE_libblock_init_empty(ID *id)
case ID_SPK:
BKE_speaker_init((Speaker *)id);
break;
+ case ID_LP:
+ BKE_lightprobe_init((LightProbe *)id);
+ break;
case ID_CA:
BKE_camera_init((Camera *)id);
break;
@@ -1270,21 +1230,47 @@ void BKE_libblock_init_empty(ID *id)
/* Should not be needed - animation from lib pre-2.5 is broken anyway. */
BLI_assert(0);
break;
+ case ID_PAL:
+ BKE_palette_init((Palette *)id);
+ break;
default:
BLI_assert(0); /* Should never reach this point... */
}
}
-/* by spec, animdata is first item after ID */
-/* and, trust that BKE_animdata_from_id() will only find AnimData for valid ID-types */
-static void id_copy_animdata(Main *bmain, ID *id, const bool do_action)
+/** Generic helper to create a new empty datablock of given type in given \a bmain database.
+ *
+ * \param name can be NULL, in which case we get default name for this ID type. */
+void *BKE_id_new(Main *bmain, const short type, const char *name)
{
- AnimData *adt = BKE_animdata_from_id(id);
+ BLI_assert(bmain != NULL);
+
+ if (name == NULL) {
+ name = DATA_(BKE_idcode_to_name(type));
+ }
+
+ ID *id = BKE_libblock_alloc(bmain, type, name, 0);
+ BKE_libblock_init_empty(id);
+
+ return id;
+}
- if (adt) {
- IdAdtTemplate *iat = (IdAdtTemplate *)id;
- iat->adt = BKE_animdata_copy(bmain, iat->adt, do_action); /* could be set to false, need to investigate */
+/** Generic helper to create a new temporary empty datablock of given type, *outside* of any Main database.
+ *
+ * \param name can be NULL, in which case we get default name for this ID type. */
+void *BKE_id_new_nomain(const short type, const char *name)
+{
+ if (name == NULL) {
+ name = DATA_(BKE_idcode_to_name(type));
}
+
+ ID *id = BKE_libblock_alloc(NULL, type, name,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG);
+ BKE_libblock_init_empty(id);
+
+ return id;
}
void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int flag)
@@ -1299,6 +1285,8 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0);
BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) != 0);
+ /* Never implicitly copy shapekeys when generating temp data outside of Main database. */
+ BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) == 0 || (flag & LIB_ID_COPY_SHAPEKEY) == 0);
if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) {
/* r_newid already contains pointer to allocated memory. */
@@ -1326,12 +1314,30 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int fla
new_id->properties = IDP_CopyProperty_ex(id->properties, flag);
}
- /* the duplicate should get a copy of the animdata */
- BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
- id_copy_animdata(bmain, new_id, (flag & LIB_ID_COPY_ACTIONS) != 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ /* XXX Again... We need a way to control what we copy in a much more refined way.
+ * We cannot always copy this, some internal copying will die on it! */
+ /* For now, upper level code will have to do that itself when required. */
+#if 0
+ if (id->override != NULL) {
+ BKE_override_copy(new_id, id);
+ }
+#endif
+
+ if (id_can_have_animdata(new_id)) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)new_id;
+
+ /* the duplicate should get a copy of the animdata */
+ if ((flag & LIB_ID_COPY_NO_ANIMDATA) == 0) {
+ BLI_assert((flag & LIB_ID_COPY_ACTIONS) == 0 || (flag & LIB_ID_CREATE_NO_MAIN) == 0);
+ iat->adt = BKE_animdata_copy(bmain, iat->adt, flag);
+ }
+ else {
+ iat->adt = NULL;
+ }
+ }
if ((flag & LIB_ID_CREATE_NO_DEG_TAG) == 0 && (flag & LIB_ID_CREATE_NO_MAIN) == 0) {
- DAG_id_type_tag(bmain, GS(new_id->name));
+ DEG_id_type_tag(bmain, GS(new_id->name));
}
*r_newid = new_id;
@@ -1362,256 +1368,6 @@ void BKE_library_free(Library *lib)
freePackedFile(lib->packedfile);
}
-Main *BKE_main_new(void)
-{
- Main *bmain = MEM_callocN(sizeof(Main), "new main");
- bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT);
- bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
- BLI_spin_init((SpinLock *)bmain->lock);
- return bmain;
-}
-
-void BKE_main_free(Main *mainvar)
-{
- /* also call when reading a file, erase all, etc */
- ListBase *lbarray[MAX_LIBARRAY];
- int a;
-
- MEM_SAFE_FREE(mainvar->blen_thumb);
-
- a = set_listbasepointers(mainvar, lbarray);
- while (a--) {
- ListBase *lb = lbarray[a];
- ID *id;
-
- while ( (id = lb->first) ) {
-#if 1
- BKE_libblock_free_ex(mainvar, id, false, false);
-#else
- /* errors freeing ID's can be hard to track down,
- * enable this so valgrind will give the line number in its error log */
- switch (a) {
- case 0: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 1: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 2: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 3: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 4: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 5: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 6: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 7: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 8: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 9: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 10: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 11: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 12: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 13: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 14: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 15: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 16: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 17: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 18: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 19: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 20: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 21: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 22: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 23: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 24: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 25: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 26: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 27: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 28: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 29: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 30: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 31: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 32: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 33: BKE_libblock_free_ex(mainvar, id, false, false); break;
- case 34: BKE_libblock_free_ex(mainvar, id, false, false); break;
- default:
- BLI_assert(0);
- break;
- }
-#endif
- }
- }
-
- if (mainvar->relations) {
- BKE_main_relations_free(mainvar);
- }
-
- BLI_spin_end((SpinLock *)mainvar->lock);
- MEM_freeN(mainvar->lock);
- DEG_evaluation_context_free(mainvar->eval_ctx);
- MEM_freeN(mainvar);
-}
-
-void BKE_main_lock(struct Main *bmain)
-{
- BLI_spin_lock((SpinLock *) bmain->lock);
-}
-
-void BKE_main_unlock(struct Main *bmain)
-{
- BLI_spin_unlock((SpinLock *) bmain->lock);
-}
-
-
-static int main_relations_create_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag)
-{
- MainIDRelations *rel = user_data;
-
- if (*id_pointer) {
- MainIDRelationsEntry *entry, **entry_p;
-
- entry = BLI_mempool_alloc(rel->entry_pool);
- if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
- entry->next = *entry_p;
- }
- else {
- entry->next = NULL;
- }
- entry->id_pointer = id_pointer;
- entry->usage_flag = cb_flag;
- *entry_p = entry;
-
- entry = BLI_mempool_alloc(rel->entry_pool);
- if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
- entry->next = *entry_p;
- }
- else {
- entry->next = NULL;
- }
- entry->id_pointer = (ID **)id_self;
- entry->usage_flag = cb_flag;
- *entry_p = entry;
- }
-
- return IDWALK_RET_NOP;
-}
-
-/** Generate the mappings between used IDs and their users, and vice-versa. */
-void BKE_main_relations_create(Main *bmain)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- ID *id;
- int a;
-
- if (bmain->relations != NULL) {
- BKE_main_relations_free(bmain);
- }
-
- bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
- bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
-
- for (a = set_listbasepointers(bmain, lbarray); a--; ) {
- for (id = lbarray[a]->first; id; id = id->next) {
- BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY);
- }
- }
-}
-
-void BKE_main_relations_free(Main *bmain)
-{
- if (bmain->relations) {
- if (bmain->relations->id_used_to_user) {
- BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
- }
- if (bmain->relations->id_user_to_used) {
- BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
- }
- BLI_mempool_destroy(bmain->relations->entry_pool);
- MEM_freeN(bmain->relations);
- bmain->relations = NULL;
- }
-}
-
-/**
- * Generates a raw .blend file thumbnail data from given image.
- *
- * \param bmain If not NULL, also store generated data in this Main.
- * \param img ImBuf image to generate thumbnail data from.
- * \return The generated .blend file raw thumbnail data.
- */
-BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
-{
- BlendThumbnail *data = NULL;
-
- if (bmain) {
- MEM_SAFE_FREE(bmain->blen_thumb);
- }
-
- if (img) {
- const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y);
- data = MEM_mallocN(sz, __func__);
-
- IMB_rect_from_float(img); /* Just in case... */
- data->width = img->x;
- data->height = img->y;
- memcpy(data->rect, img->rect, sz - sizeof(*data));
- }
-
- if (bmain) {
- bmain->blen_thumb = data;
- }
- return data;
-}
-
-/**
- * Generates an image from raw .blend file thumbnail \a data.
- *
- * \param bmain Use this bmain->blen_thumb data if given \a data is NULL.
- * \param data Raw .blend file thumbnail data.
- * \return An ImBuf from given data, or NULL if invalid.
- */
-ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
-{
- ImBuf *img = NULL;
-
- if (!data && bmain) {
- data = bmain->blen_thumb;
- }
-
- if (data) {
- /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail
- * here (we do not want to pass the first two ints!). */
- img = IMB_allocImBuf((unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata);
- memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data));
- }
-
- return img;
-}
-
-/**
- * Generates an empty (black) thumbnail for given Main.
- */
-void BKE_main_thumbnail_create(struct Main *bmain)
-{
- MEM_SAFE_FREE(bmain->blen_thumb);
-
- bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__);
- bmain->blen_thumb->width = BLEN_THUMB_SIZE;
- bmain->blen_thumb->height = BLEN_THUMB_SIZE;
-}
-
-/**
- * Return filepath of given \a main.
- */
-const char *BKE_main_blendfile_path(const Main *bmain)
-{
- return bmain->name;
-}
-
-/**
- * Return filepath of global main (G_MAIN).
- *
- * \warning Usage is not recommended, you should always try to get a valid Main pointer from context...
- */
-const char *BKE_main_blendfile_path_from_global(void)
-{
- return BKE_main_blendfile_path(G_MAIN);
-}
-
/* ***************** ID ************************ */
ID *BKE_libblock_find_name(struct Main *bmain, const short type, const char *name)
{
@@ -2320,7 +2076,7 @@ void BKE_library_make_local(
* Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */
for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->data != NULL && ob->type == OB_ARMATURE && ob->pose != NULL && ob->pose->flag & POSE_RECALC) {
- BKE_pose_rebuild(ob, ob->data);
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
}
}
@@ -2368,16 +2124,58 @@ void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
}
/**
- * Returns in name the name of the block, with a 3-character prefix prepended
- * indicating whether it comes from a library, has a fake user, or no users.
+ * Generate full name of the data-block (without ID code, but with library is any)
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name An allocated string of minimal length MAX_ID_FULL_NAME, will be filled with generated string.
+ */
+void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id)
+{
+ strcpy(name, id->name + 2);
+
+ if (id->lib != NULL) {
+ const size_t idname_len = strlen(id->name + 2);
+ const size_t libname_len = strlen(id->lib->id.name + 2);
+
+ name[idname_len] = ' ';
+ name[idname_len + 1] = '[';
+ strcpy(name + idname_len + 2, id->lib->id.name + 2);
+ name[idname_len + 2 + libname_len] = ']';
+ name[idname_len + 2 + libname_len + 1] = '\0';
+ }
+}
+
+/**
+ * Generate full name of the data-block (without ID code, but with library is any), with a 3-character prefix prepended
+ * indicating whether it comes from a library, is overriding, has a fake or no user, etc.
+ *
+ * \note Result is unique to a given ID type in a given Main database.
+ *
+ * \param name An allocated string of minimal length MAX_ID_FULL_NAME_UI, will be filled with generated string.
*/
-void BKE_id_ui_prefix(char name[MAX_ID_NAME + 1], const ID *id)
+void BKE_id_full_name_ui_prefix_get(char name[MAX_ID_FULL_NAME_UI], const ID *id)
{
- name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ' ';
+ name[0] = id->lib ? (ID_MISSING(id) ? 'M' : 'L') : ID_IS_STATIC_OVERRIDE(id) ? 'O' : ' ';
name[1] = (id->flag & LIB_FAKEUSER) ? 'F' : ((id->us == 0) ? '0' : ' ');
name[2] = ' ';
- strcpy(name + 3, id->name + 2);
+ BKE_id_full_name_get(name + 3, id);
+}
+
+/**
+ * Generate a concatenation of ID name (including two-chars type code) and its lib name, if any.
+ *
+ * \return A unique allocated string key for any ID in the whole Main database.
+ */
+char *BKE_id_to_unique_string_key(const struct ID *id)
+{
+ char name[MAX_ID_FULL_NAME + 2];
+ name[0] = id->name[0];
+ name[1] = id->name[1];
+ BKE_id_full_name_get(name + 2, id);
+
+ return BLI_strdup(name);
}
void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath)
@@ -2417,8 +2215,103 @@ void BKE_id_tag_clear_atomic(ID *id, int tag)
/** Check that given ID pointer actually is in G_MAIN.
* Main intended use is for debug asserts in places we cannot easily get rid of G_Main... */
-bool BKE_id_is_in_gobal_main(ID *id)
+bool BKE_id_is_in_global_main(ID *id)
{
/* We do not want to fail when id is NULL here, even though this is a bit strange behavior... */
return (id == NULL || BLI_findindex(which_libbase(G_MAIN, GS(id->name)), id) != -1);
}
+
+/************************* Datablock order in UI **************************/
+
+static int *id_order_get(ID *id)
+{
+ /* Only for workspace tabs currently. */
+ switch (GS(id->name)) {
+ case ID_WS:
+ return &((WorkSpace *)id)->order;
+ default:
+ return NULL;
+ }
+}
+
+static int id_order_compare(const void *a, const void *b)
+{
+ ID *id_a = ((LinkData *)a)->data;
+ ID *id_b = ((LinkData *)b)->data;
+
+ int *order_a = id_order_get(id_a);
+ int *order_b = id_order_get(id_b);
+
+ if (order_a && order_b) {
+ if (*order_a < *order_b) {
+ return -1;
+ }
+ else if (*order_a > *order_b) {
+ return 1;
+ }
+ }
+
+ return strcmp(id_a->name, id_b->name);
+}
+
+/**
+ * Returns ordered list of datablocks for display in the UI.
+ * Result is list of LinkData of IDs that must be freed.
+ */
+void BKE_id_ordered_list(ListBase *ordered_lb, const ListBase *lb)
+{
+ BLI_listbase_clear(ordered_lb);
+
+ for (ID *id = lb->first; id; id = id->next) {
+ BLI_addtail(ordered_lb, BLI_genericNodeN(id));
+ }
+
+ BLI_listbase_sort(ordered_lb, id_order_compare);
+
+ int num = 0;
+ for (LinkData *link = ordered_lb->first; link; link = link->next) {
+ int *order = id_order_get(link->data);
+ if (order) {
+ *order = num++;
+ }
+ }
+}
+
+/**
+ * Reorder ID in the list, before or after the "relative" ID.
+ */
+void BKE_id_reorder(const ListBase *lb, ID *id, ID *relative, bool after)
+{
+ int *id_order = id_order_get(id);
+ int relative_order;
+
+ if (relative) {
+ relative_order = *id_order_get(relative);
+ }
+ else {
+ relative_order = (after) ? BLI_listbase_count(lb) : 0;
+ }
+
+ if (after) {
+ /* Insert after. */
+ for (ID *other = lb->first; other; other = other->next) {
+ int *order = id_order_get(other);
+ if (*order > relative_order) {
+ (*order)++;
+ }
+ }
+
+ *id_order = relative_order + 1;
+ }
+ else {
+ /* Insert before. */
+ for (ID *other = lb->first; other; other = other->next) {
+ int *order = id_order_get(other);
+ if (*order < relative_order) {
+ (*order)--;
+ }
+ }
+
+ *id_order = relative_order - 1;
+ }
+}
diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c
index daf097b9f0b..1cc13b39a97 100644
--- a/source/blender/blenkernel/intern/library_idmap.c
+++ b/source/blender/blenkernel/intern/library_idmap.c
@@ -32,6 +32,7 @@
#include "BKE_idcode.h"
#include "BKE_library.h"
#include "BKE_library_idmap.h" /* own include */
+#include "BKE_main.h"
/** \file blender/blenkernel/intern/library_idmap.c
* \ingroup bke
diff --git a/source/blender/blenkernel/intern/library_override.c b/source/blender/blenkernel/intern/library_override.c
new file mode 100644
index 00000000000..714730b2f52
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_override.c
@@ -0,0 +1,789 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Bastien Montagne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/library_override.c
+ * \ingroup bke
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_object_types.h"
+
+#include "DEG_depsgraph.h"
+#include "BKE_library.h"
+#include "BKE_library_override.h"
+#include "BKE_library_remap.h"
+#include "BKE_main.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "PIL_time.h"
+#include "PIL_time_utildefines.h"
+
+#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */
+
+static void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src);
+static void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src);
+
+static void bke_override_property_clear(IDOverrideStaticProperty *op);
+static void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop);
+
+/* Temp, for until static override is ready and tested enough to go 'public', we hide it by default in UI and such. */
+static bool _override_static_enabled = false;
+
+void BKE_override_static_enable(const bool do_enable)
+{
+ _override_static_enabled = do_enable;
+}
+
+bool BKE_override_static_is_enabled()
+{
+ return _override_static_enabled;
+}
+
+/** Initialize empty overriding of \a reference_id by \a local_id. */
+IDOverrideStatic *BKE_override_static_init(ID *local_id, ID *reference_id)
+{
+ /* If reference_id is NULL, we are creating an override template for purely local data.
+ * Else, reference *must* be linked data. */
+ BLI_assert(reference_id == NULL || reference_id->lib != NULL);
+ BLI_assert(local_id->override_static == NULL);
+
+ ID *ancestor_id;
+ for (ancestor_id = reference_id;
+ ancestor_id != NULL && ancestor_id->override_static != NULL && ancestor_id->override_static->reference != NULL;
+ ancestor_id = ancestor_id->override_static->reference);
+
+ if (ancestor_id != NULL && ancestor_id->override_static != NULL) {
+ /* Original ID has a template, use it! */
+ BKE_override_static_copy(local_id, ancestor_id);
+ if (local_id->override_static->reference != reference_id) {
+ id_us_min(local_id->override_static->reference);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(local_id->override_static->reference);
+ }
+ return local_id->override_static;
+ }
+
+ /* Else, generate new empty override. */
+ local_id->override_static = MEM_callocN(sizeof(*local_id->override_static), __func__);
+ local_id->override_static->reference = reference_id;
+ id_us_plus(local_id->override_static->reference);
+ local_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ /* TODO do we want to add tag or flag to referee to mark it as such? */
+ return local_id->override_static;
+}
+
+/** Deep copy of a whole override from \a src_id to \a dst_id. */
+void BKE_override_static_copy(ID *dst_id, const ID *src_id)
+{
+ BLI_assert(src_id->override_static != NULL);
+
+ if (dst_id->override_static != NULL) {
+ if (src_id->override_static == NULL) {
+ BKE_override_static_free(&dst_id->override_static);
+ return;
+ }
+ else {
+ BKE_override_static_clear(dst_id->override_static);
+ }
+ }
+ else if (src_id->override_static == NULL) {
+ return;
+ }
+ else {
+ BKE_override_static_init(dst_id, NULL);
+ }
+
+ /* Source is already overriding data, we copy it but reuse its reference for dest ID.
+ * otherwise, source is only an override template, it then becomes reference of dest ID. */
+ dst_id->override_static->reference = src_id->override_static->reference ? src_id->override_static->reference : (ID *)src_id;
+ id_us_plus(dst_id->override_static->reference);
+
+ BLI_duplicatelist(&dst_id->override_static->properties, &src_id->override_static->properties);
+ for (IDOverrideStaticProperty *op_dst = dst_id->override_static->properties.first, *op_src = src_id->override_static->properties.first;
+ op_dst;
+ op_dst = op_dst->next, op_src = op_src->next)
+ {
+ bke_override_property_copy(op_dst, op_src);
+ }
+
+ dst_id->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+}
+
+/** Clear any overriding data from given \a override. */
+void BKE_override_static_clear(IDOverrideStatic *override)
+{
+ BLI_assert(override != NULL);
+
+ for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+ bke_override_property_clear(op);
+ }
+ BLI_freelistN(&override->properties);
+
+ id_us_min(override->reference);
+ /* override->storage should never be refcounted... */
+}
+
+/** Free given \a override. */
+void BKE_override_static_free(struct IDOverrideStatic **override)
+{
+ BLI_assert(*override != NULL);
+
+ BKE_override_static_clear(*override);
+ MEM_freeN(*override);
+ *override = NULL;
+}
+
+static ID *override_static_create_from(Main *bmain, ID *reference_id)
+{
+ ID *local_id;
+
+ if (!id_copy(bmain, reference_id, (ID **)&local_id, false)) {
+ return NULL;
+ }
+ id_us_min(local_id);
+
+ BKE_override_static_init(local_id, reference_id);
+ local_id->override_static->flag |= STATICOVERRIDE_AUTO;
+
+ return local_id;
+}
+
+
+/** Create an overridden local copy of linked reference. */
+ID *BKE_override_static_create_from_id(Main *bmain, ID *reference_id)
+{
+ BLI_assert(reference_id != NULL);
+ BLI_assert(reference_id->lib != NULL);
+
+ ID *local_id = override_static_create_from(bmain, reference_id);
+
+ /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */
+ BKE_libblock_remap(bmain, reference_id, local_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+
+ return local_id;
+}
+
+/** Create overridden local copies of all tagged data-blocks in given Main.
+ *
+ * \note Set id->newid of overridden libs with newly created overrides, caller is responsible to clean those pointers
+ * before/after usage as needed.
+ *
+ * \return \a true on success, \a false otherwise.
+ */
+bool BKE_override_static_create_from_tag(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+ bool ret = true;
+
+ const int num_types = a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL) {
+ if ((reference_id->newid = override_static_create_from(bmain, reference_id)) == NULL) {
+ ret = false;
+ }
+ }
+ }
+ }
+
+ /* Remapping, we obviously only want to affect local data (and not our own reference pointer to overridden ID). */
+ a = num_types;
+ while (a--) {
+ for (ID *reference_id = lbarray[a]->first; reference_id != NULL; reference_id = reference_id->next) {
+ if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib != NULL && reference_id->newid != NULL) {
+ ID *local_id = reference_id->newid;
+ BKE_libblock_remap(bmain, reference_id, local_id,
+ ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_STATIC_OVERRIDE);
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Find override property from given RNA path, if it exists.
+ */
+IDOverrideStaticProperty *BKE_override_static_property_find(IDOverrideStatic *override, const char *rna_path)
+{
+ /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
+ return BLI_findstring_ptr(&override->properties, rna_path, offsetof(IDOverrideStaticProperty, rna_path));
+}
+
+/**
+ * Find override property from given RNA path, or create it if it does not exist.
+ */
+IDOverrideStaticProperty *BKE_override_static_property_get(IDOverrideStatic *override, const char *rna_path, bool *r_created)
+{
+ /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
+ IDOverrideStaticProperty *op = BKE_override_static_property_find(override, rna_path);
+
+ if (op == NULL) {
+ op = MEM_callocN(sizeof(IDOverrideStaticProperty), __func__);
+ op->rna_path = BLI_strdup(rna_path);
+ BLI_addtail(&override->properties, op);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return op;
+}
+
+void bke_override_property_copy(IDOverrideStaticProperty *op_dst, IDOverrideStaticProperty *op_src)
+{
+ op_dst->rna_path = BLI_strdup(op_src->rna_path);
+ BLI_duplicatelist(&op_dst->operations, &op_src->operations);
+
+ for (IDOverrideStaticPropertyOperation *opop_dst = op_dst->operations.first, *opop_src = op_src->operations.first;
+ opop_dst;
+ opop_dst = opop_dst->next, opop_src = opop_src->next)
+ {
+ bke_override_property_operation_copy(opop_dst, opop_src);
+ }
+}
+
+void bke_override_property_clear(IDOverrideStaticProperty *op)
+{
+ BLI_assert(op->rna_path != NULL);
+
+ MEM_freeN(op->rna_path);
+
+ for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+ bke_override_property_operation_clear(opop);
+ }
+ BLI_freelistN(&op->operations);
+}
+
+/**
+ * Remove and free given \a override_property from given ID \a override.
+ */
+void BKE_override_static_property_delete(IDOverrideStatic *override, IDOverrideStaticProperty *override_property)
+{
+ bke_override_property_clear(override_property);
+ BLI_freelinkN(&override->properties, override_property);
+}
+
+/**
+ * Find override property operation from given sub-item(s), if it exists.
+ */
+IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_find(
+ IDOverrideStaticProperty *override_property,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex, const bool strict, bool *r_strict)
+{
+ IDOverrideStaticPropertyOperation *opop;
+ const int subitem_defindex = -1;
+
+ if (r_strict) {
+ *r_strict = true;
+ }
+
+ if (subitem_locname != NULL) {
+ opop = BLI_findstring_ptr(&override_property->operations, subitem_locname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_name));
+
+ if (opop == NULL) {
+ return NULL;
+ }
+
+ if (subitem_refname == NULL || opop->subitem_reference_name == NULL) {
+ return subitem_refname == opop->subitem_reference_name ? opop : NULL;
+ }
+ return (subitem_refname != NULL && opop->subitem_reference_name != NULL &&
+ STREQ(subitem_refname, opop->subitem_reference_name)) ? opop : NULL;
+ }
+
+ if (subitem_refname != NULL) {
+ opop = BLI_findstring_ptr(&override_property->operations, subitem_refname,
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_name));
+
+ if (opop == NULL) {
+ return NULL;
+ }
+
+ if (subitem_locname == NULL || opop->subitem_local_name == NULL) {
+ return subitem_locname == opop->subitem_local_name ? opop : NULL;
+ }
+ return (subitem_locname != NULL && opop->subitem_local_name != NULL &&
+ STREQ(subitem_locname, opop->subitem_local_name)) ? opop : NULL;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_locindex, sizeof(subitem_locindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
+ {
+ return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL;
+ }
+
+ if ((opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_refindex, sizeof(subitem_refindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_reference_index))))
+ {
+ return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL;
+ }
+
+ /* index == -1 means all indices, that is valid fallback in case we requested specific index. */
+ if (!strict && (subitem_locindex != subitem_defindex) &&
+ (opop = BLI_listbase_bytes_find(&override_property->operations, &subitem_defindex, sizeof(subitem_defindex),
+ offsetof(IDOverrideStaticPropertyOperation, subitem_local_index))))
+ {
+ if (r_strict) {
+ *r_strict = false;
+ }
+ return opop;
+ }
+
+ return NULL;
+}
+
+/**
+ * Find override property operation from given sub-item(s), or create it if it does not exist.
+ */
+IDOverrideStaticPropertyOperation *BKE_override_static_property_operation_get(
+ IDOverrideStaticProperty *override_property, const short operation,
+ const char *subitem_refname, const char *subitem_locname,
+ const int subitem_refindex, const int subitem_locindex,
+ const bool strict, bool *r_strict, bool *r_created)
+{
+ IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(override_property,
+ subitem_refname, subitem_locname,
+ subitem_refindex, subitem_locindex,
+ strict, r_strict);
+
+ if (opop == NULL) {
+ opop = MEM_callocN(sizeof(IDOverrideStaticPropertyOperation), __func__);
+ opop->operation = operation;
+ if (subitem_locname) {
+ opop->subitem_local_name = BLI_strdup(subitem_locname);
+ }
+ if (subitem_refname) {
+ opop->subitem_reference_name = BLI_strdup(subitem_refname);
+ }
+ opop->subitem_local_index = subitem_locindex;
+ opop->subitem_reference_index = subitem_refindex;
+
+ BLI_addtail(&override_property->operations, opop);
+
+ if (r_created) {
+ *r_created = true;
+ }
+ }
+ else if (r_created) {
+ *r_created = false;
+ }
+
+ return opop;
+}
+
+void bke_override_property_operation_copy(IDOverrideStaticPropertyOperation *opop_dst, IDOverrideStaticPropertyOperation *opop_src)
+{
+ if (opop_src->subitem_reference_name) {
+ opop_dst->subitem_reference_name = BLI_strdup(opop_src->subitem_reference_name);
+ }
+ if (opop_src->subitem_local_name) {
+ opop_dst->subitem_local_name = BLI_strdup(opop_src->subitem_local_name);
+ }
+}
+
+void bke_override_property_operation_clear(IDOverrideStaticPropertyOperation *opop)
+{
+ if (opop->subitem_reference_name) {
+ MEM_freeN(opop->subitem_reference_name);
+ }
+ if (opop->subitem_local_name) {
+ MEM_freeN(opop->subitem_local_name);
+ }
+}
+
+/**
+ * Remove and free given \a override_property_operation from given ID \a override_property.
+ */
+void BKE_override_static_property_operation_delete(
+ IDOverrideStaticProperty *override_property, IDOverrideStaticPropertyOperation *override_property_operation)
+{
+ bke_override_property_operation_clear(override_property_operation);
+ BLI_freelinkN(&override_property->operations, override_property_operation);
+}
+
+/**
+ * Check that status of local data-block is still valid against current reference one.
+ *
+ * It means that all overridable, but not overridden, properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some property has been changed in local and a new IDOverrideProperty
+ * (of IDOverridePropertyOperation) has to be added.
+ *
+ * \return true if status is OK, false otherwise. */
+bool BKE_override_static_status_check_local(Main *bmain, ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ ID *reference = local->override_static->reference;
+
+ if (reference == NULL) {
+ /* This is an override template, local status is always OK! */
+ return true;
+ }
+
+ BLI_assert(GS(local->name) == GS(reference->name));
+
+ /* Note that reference is assumed always valid, caller has to ensure that itself. */
+
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
+
+ if (!RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE | RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
+ {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Check that status of reference data-block is still valid against current local one.
+ *
+ * It means that all non-overridden properties' local values must be equal to reference ones.
+ * Clears LIB_TAG_OVERRIDE_OK if they do not.
+ *
+ * This is typically used to detect whether some reference has changed and local needs to be updated against it.
+ *
+ * \return true if status is OK, false otherwise. */
+bool BKE_override_static_status_check_reference(Main *bmain, ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ ID *reference = local->override_static->reference;
+
+ if (reference == NULL) {
+ /* This is an override template, reference is virtual, so its status is always OK! */
+ return true;
+ }
+
+ BLI_assert(GS(local->name) == GS(reference->name));
+
+ if (reference->override_static && (reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
+ if (!BKE_override_static_status_check_reference(bmain, reference)) {
+ /* If reference is also override of another data-block, and its status is not OK,
+ * then this override is not OK either.
+ * Note that this should only happen when reloading libraries... */
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+ }
+
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(reference, &rnaptr_reference);
+
+ if (!RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN, NULL))
+ {
+ local->tag &= ~LIB_TAG_OVERRIDESTATIC_REFOK;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Compares local and reference data-blocks and create new override operations as needed,
+ * or reset to reference values if overriding is not allowed.
+ *
+ * \note Defining override operations is only mandatory before saving a .blend file on disk (not for undo!).
+ * Knowing that info at runtime is only useful for UI/UX feedback.
+ *
+ * \note This is by far the biggest operation (the more time-consuming) of the three so far, since it has to go over
+ * all properties in depth (all overridable ones at least). Generating diff values and applying overrides
+ * are much cheaper.
+ *
+ * \return true if new overriding op was created, or some local data was reset. */
+bool BKE_override_static_operations_create(Main *bmain, ID *local, const bool force_auto)
+{
+ BLI_assert(local->override_static != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
+ bool ret = false;
+
+ if (!is_template && (force_auto || local->override_static->flag & STATICOVERRIDE_AUTO)) {
+ PointerRNA rnaptr_local, rnaptr_reference;
+ RNA_id_pointer_create(local, &rnaptr_local);
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+
+ eRNAOverrideMatchResult report_flags = 0;
+ RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local, &rnaptr_reference, NULL, local->override_static,
+ RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE, &report_flags);
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
+ ret = true;
+ }
+#ifndef NDEBUG
+ if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
+ printf("We did restore some properties of %s from its reference.\n", local->name);
+ }
+ if (ret) {
+ printf("We did generate static override rules for %s\n", local->name);
+ }
+ else {
+ printf("No new static override rules for %s\n", local->name);
+ }
+#endif
+ }
+ return ret;
+}
+
+/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
+void BKE_main_override_static_operations_create(Main *bmain, const bool force_auto)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (force_auto ||
+ (ID_IS_STATIC_OVERRIDE_AUTO(id) && (id->tag & LIB_TAG_OVERRIDESTATIC_AUTOREFRESH)))
+ {
+ BKE_override_static_operations_create(bmain, id, force_auto);
+ id->tag &= ~LIB_TAG_OVERRIDESTATIC_AUTOREFRESH;
+ }
+ }
+ }
+}
+
+/** Update given override from its reference (re-applying overridden properties). */
+void BKE_override_static_update(Main *bmain, ID *local)
+{
+ if (local->override_static == NULL || local->override_static->reference == NULL) {
+ return;
+ }
+
+ /* Recursively do 'ancestors' overrides first, if any. */
+ if (local->override_static->reference->override_static && (local->override_static->reference->tag & LIB_TAG_OVERRIDESTATIC_REFOK) == 0) {
+ BKE_override_static_update(bmain, local->override_static->reference);
+ }
+
+ /* We want to avoid having to remap here, however creating up-to-date override is much simpler if based
+ * on reference than on current override.
+ * So we work on temp copy of reference, and 'swap' its content with local. */
+
+ /* XXX We need a way to get off-Main copies of IDs (similar to localized mats/texts/ etc.)!
+ * However, this is whole bunch of code work in itself, so for now plain stupid ID copy will do,
+ * as innefficient as it is. :/
+ * Actually, maybe not! Since we are swapping with original ID's local content, we want to keep
+ * usercount in correct state when freeing tmp_id (and that usercounts of IDs used by 'new' local data
+ * also remain correct). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first if extra useless usual user handling is actually
+ * a (performances) issue here. */
+
+ ID *tmp_id;
+ id_copy(bmain, local->override_static->reference, &tmp_id, false);
+
+ if (tmp_id == NULL) {
+ return;
+ }
+
+ PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL;
+ RNA_id_pointer_create(local, &rnaptr_src);
+ RNA_id_pointer_create(tmp_id, &rnaptr_dst);
+ if (local->override_static->storage) {
+ rnaptr_storage = &rnaptr_storage_stack;
+ RNA_id_pointer_create(local->override_static->storage, rnaptr_storage);
+ }
+
+ RNA_struct_override_apply(bmain, &rnaptr_dst, &rnaptr_src, rnaptr_storage, local->override_static);
+
+ /* This also transfers all pointers (memory) owned by local to tmp_id, and vice-versa. So when we'll free tmp_id,
+ * we'll actually free old, outdated data from local. */
+ BKE_id_swap(bmain, local, tmp_id);
+
+ /* Again, horribly innefficient in our case, we need something off-Main (aka moar generic nolib copy/free stuff)! */
+ /* XXX And crashing in complex cases (e.g. because depsgraph uses same data...). */
+ BKE_libblock_free_ex(bmain, tmp_id, true, false);
+
+ if (local->override_static->storage) {
+ /* We know this datablock is not used anywhere besides local->override->storage. */
+ /* XXX For until we get fully shadow copies, we still need to ensure storage releases
+ * its usage of any ID pointers it may have. */
+ BKE_libblock_free_ex(bmain, local->override_static->storage, true, false);
+ local->override_static->storage = NULL;
+ }
+
+ local->tag |= LIB_TAG_OVERRIDESTATIC_REFOK;
+
+ /* Full rebuild of Depsgraph! */
+ DEG_on_visible_update(bmain, true); /* XXX Is this actual valid replacement for old DAG_relations_tag_update(bmain) ? */
+}
+
+/** Update all overrides from given \a bmain. */
+void BKE_main_override_static_update(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(bmain, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ for (id = lb->first; id; id = id->next) {
+ if (id->override_static != NULL && id->lib == NULL) {
+ BKE_override_static_update(bmain, id);
+ }
+ }
+ }
+}
+
+/***********************************************************************************************************************
+ * Storage (how to wtore overriding data into .blend files).
+ *
+ * Basically:
+ * I) Only 'differential' storage needs special handling here. All others (replacing values or
+ * inserting/removing items from a collection) can be handled with simply storing current content of local data-block.
+ * II) We store the differential value into a second 'ghost' data-block, which is an empty ID of same type as local one,
+ * where we only define values that need differential data.
+ *
+ * This avoids us having to modify 'real' data-block at write time (and restoring it afterwards), which is inneficient,
+ * and potentially dangerous (in case of concurrent access...), while not using much extra memory in typical cases.
+ * It also ensures stored data-block always contains exact same data as "desired" ones (kind of "baked" data-blocks).
+ */
+
+/** Initialize an override storage. */
+OverrideStaticStorage *BKE_override_static_operations_store_initialize(void)
+{
+ return BKE_main_new();
+}
+
+/**
+ * Generate suitable 'write' data (this only affects differential override operations).
+ *
+ * Note that \a local ID is no more modified by this call, all extra data are stored in its temp \a storage_id copy. */
+ID *BKE_override_static_operations_store_start(Main *bmain, OverrideStaticStorage *override_storage, ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+ BLI_assert(override_storage != NULL);
+ const bool is_template = (local->override_static->reference == NULL);
+
+ if (is_template) {
+ /* This is actually purely local data with an override template, nothing to do here! */
+ return NULL;
+ }
+
+ /* Forcefully ensure we know about all needed override operations. */
+ BKE_override_static_operations_create(bmain, local, false);
+
+ ID *storage_id;
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_START_AVERAGED(BKE_override_operations_store_start);
+#endif
+
+ /* XXX TODO We may also want a specialized handling of things here too, to avoid copying heavy never-overridable
+ * data (like Mesh geometry etc.)? And also maybe avoid lib refcounting completely (shallow copy...). */
+ /* This would imply change in handling of usercout all over RNA (and possibly all over Blender code).
+ * Not impossible to do, but would rather see first is extra useless usual user handling is actually
+ * a (performances) issue here, before doing it. */
+ id_copy((Main *)override_storage, local, &storage_id, false);
+
+ if (storage_id != NULL) {
+ PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage;
+ RNA_id_pointer_create(local->override_static->reference, &rnaptr_reference);
+ RNA_id_pointer_create(local, &rnaptr_final);
+ RNA_id_pointer_create(storage_id, &rnaptr_storage);
+
+ if (!RNA_struct_override_store(
+ bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_static))
+ {
+ BKE_libblock_free_ex(override_storage, storage_id, true, false);
+ storage_id = NULL;
+ }
+ }
+
+ local->override_static->storage = storage_id;
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+ TIMEIT_END_AVERAGED(BKE_override_operations_store_start);
+#endif
+ return storage_id;
+}
+
+/** Restore given ID modified by \a BKE_override_operations_store_start, to its original state. */
+void BKE_override_static_operations_store_end(OverrideStaticStorage *UNUSED(override_storage), ID *local)
+{
+ BLI_assert(local->override_static != NULL);
+
+ /* Nothing else to do here really, we need to keep all temp override storage data-blocks in memory until
+ * whole file is written anyway (otherwise we'd get mem pointers overlap...). */
+ local->override_static->storage = NULL;
+}
+
+void BKE_override_static_operations_store_finalize(OverrideStaticStorage *override_storage)
+{
+ /* We cannot just call BKE_main_free(override_storage), not until we have option to make 'ghost' copies of IDs
+ * without increasing usercount of used data-blocks... */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int base_count, i;
+
+ base_count = set_listbasepointers(override_storage, lbarray);
+
+ for (i = 0; i < base_count; i++) {
+ ListBase *lb = lbarray[i];
+ ID *id;
+
+ while ((id = lb->first)) {
+ BKE_libblock_free_ex(override_storage, id, true, false);
+ }
+ }
+
+ BKE_main_free(override_storage);
+}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index d59658a2a07..ea1b35e4c1e 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -31,14 +31,12 @@
#include "MEM_guardedalloc.h"
-#include "DNA_actuator_types.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_group_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
@@ -52,15 +50,17 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_force_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "DNA_sensor_types.h"
#include "DNA_sequence_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
#include "DNA_sound_types.h"
#include "DNA_text_types.h"
#include "DNA_vfont_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "BLI_utildefines.h"
@@ -69,8 +69,10 @@
#include "BLI_linklist_stack.h"
#include "BKE_animsys.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -79,9 +81,9 @@
#include "BKE_node.h"
#include "BKE_particle.h"
#include "BKE_rigidbody.h"
-#include "BKE_sca.h"
#include "BKE_sequencer.h"
#include "BKE_tracking.h"
+#include "BKE_workspace.h"
#define FOREACH_FINALIZE _finalize
@@ -194,27 +196,8 @@ static void library_foreach_modifiersForeachIDLink(
FOREACH_FINALIZE_VOID;
}
-static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer,
- bool is_reference, void *user_data)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_particlesystemsObjectLooper(
- ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag)
-{
- LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
- FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
-
- FOREACH_FINALIZE_VOID;
-}
-
-static void library_foreach_sensorsObjectLooper(
- bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cb_flag)
+static void library_foreach_gpencil_modifiersForeachIDLink(
+ void *user_data, Object *UNUSED(object), ID **id_pointer, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
@@ -222,17 +205,18 @@ static void library_foreach_sensorsObjectLooper(
FOREACH_FINALIZE_VOID;
}
-static void library_foreach_controllersObjectLooper(
- bController *UNUSED(controller), ID **id_pointer, void *user_data, int cb_flag)
+static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer,
+ bool is_reference, void *user_data)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
+ const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP;
FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
FOREACH_FINALIZE_VOID;
}
-static void library_foreach_actuatorsObjectLooper(
- bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cb_flag)
+static void library_foreach_particlesystemsObjectLooper(
+ ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag)
{
LibraryForeachIDData *data = (LibraryForeachIDData *) user_data;
FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag);
@@ -296,6 +280,9 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex)
static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint)
{
FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER);
+ for (int i = 0; i < paint->tool_slots_len; i++) {
+ FOREACH_CALLBACK_INVOKE(data, paint->tool_slots[i].brush, IDWALK_CB_USER);
+ }
FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER);
FOREACH_FINALIZE_VOID;
@@ -312,6 +299,16 @@ static void library_foreach_bone(LibraryForeachIDData *data, Bone *bone)
FOREACH_FINALIZE_VOID;
}
+static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb)
+{
+ for (LayerCollection *lc = lb->first; lc; lc = lc->next) {
+ FOREACH_CALLBACK_INVOKE(data, lc->collection, IDWALK_CB_NOP);
+ library_foreach_layer_collection(data, &lc->layer_collections);
+ }
+
+ FOREACH_FINALIZE_VOID;
+}
+
static void library_foreach_ID_as_subdata_link(
ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data)
{
@@ -384,6 +381,11 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
continue;
}
+ if (id->override_static != NULL) {
+ CALLBACK_INVOKE_ID(id->override_static->reference, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
+ CALLBACK_INVOKE_ID(id->override_static->storage, IDWALK_CB_USER | IDWALK_CB_STATIC_OVERRIDE_REFERENCE);
+ }
+
library_foreach_idproperty_ID_link(&data, id->properties, IDWALK_CB_USER);
AnimData *adt = BKE_animdata_from_id(id);
@@ -402,8 +404,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
{
Scene *scene = (Scene *) id;
ToolSettings *toolsett = scene->toolsettings;
- SceneRenderLayer *srl;
- Base *base;
CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP);
CALLBACK_INVOKE(scene->world, IDWALK_CB_USER);
@@ -413,35 +413,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&scene->nodetree, callback, user_data, flag, &data);
}
- /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later,
- * since basact is just a pointer to one of those items. */
- CALLBACK_INVOKE(scene->obedit, IDWALK_CB_NOP);
-
- for (srl = scene->r.layers.first; srl; srl = srl->next) {
- FreestyleModuleConfig *fmc;
- FreestyleLineSet *fls;
-
- if (srl->mat_override) {
- CALLBACK_INVOKE(srl->mat_override, IDWALK_CB_USER);
- }
- if (srl->light_override) {
- CALLBACK_INVOKE(srl->light_override, IDWALK_CB_USER);
- }
- for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
- if (fmc->script) {
- CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
- }
- }
- for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
- if (fls->group) {
- CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
- }
- if (fls->linestyle) {
- CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
- }
- }
- }
-
if (scene->ed) {
Sequence *seq;
SEQP_BEGIN(scene->ed, seq)
@@ -459,10 +430,37 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
SEQ_END
}
- CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
- for (base = scene->base.first; base; base = base->next) {
- CALLBACK_INVOKE(base->object, IDWALK_CB_USER);
+ for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) {
+ CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
+ }
+ for (CollectionChild *child = scene->master_collection->children.first; child; child = child->next) {
+ CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
+ }
+
+ ViewLayer *view_layer;
+ for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ CALLBACK_INVOKE(base->object, IDWALK_CB_NOP);
+ }
+
+ library_foreach_layer_collection(&data, &view_layer->layer_collections);
+
+ for (FreestyleModuleConfig *fmc = view_layer->freestyle_config.modules.first; fmc; fmc = fmc->next) {
+ if (fmc->script) {
+ CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP);
+ }
+ }
+
+ for (FreestyleLineSet *fls = view_layer->freestyle_config.linesets.first; fls; fls = fls->next) {
+ if (fls->group) {
+ CALLBACK_INVOKE(fls->group, IDWALK_CB_USER);
+ }
+
+ if (fls->linestyle) {
+ CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER);
+ }
+ }
}
for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
@@ -470,8 +468,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
if (toolsett) {
- CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_CB_NOP);
-
CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP);
CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP);
CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP);
@@ -494,14 +490,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
if (toolsett->uvsculpt) {
library_foreach_paint(&data, &toolsett->uvsculpt->paint);
}
+ if (toolsett->gp_paint) {
+ library_foreach_paint(&data, &toolsett->gp_paint->paint);
+ }
}
if (scene->rigidbody_world) {
BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data);
}
- CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_CB_NOP);
-
break;
}
@@ -586,6 +583,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
modifiers_foreachIDLink(object, library_foreach_modifiersForeachIDLink, &data);
+ BKE_gpencil_modifiers_foreachIDLink(object, library_foreach_gpencil_modifiersForeachIDLink, &data);
BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, &data);
for (psys = object->particlesystem.first; psys; psys = psys->next) {
@@ -599,10 +597,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP);
}
}
-
- BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data);
- BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data);
- BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data);
break;
}
@@ -624,31 +618,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
for (i = 0; i < mesh->totcol; i++) {
CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER);
}
-
- /* XXX Really not happy with this - probably texface should rather use some kind of
- * 'texture slots' and just set indices in each poly/face item - would also save some memory.
- * Maybe a nice TODO for blender2.8? */
- if (mesh->mtface || mesh->mtpoly) {
- for (i = 0; i < mesh->pdata.totlayer; i++) {
- if (mesh->pdata.layers[i].type == CD_MTEXPOLY) {
- MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data;
-
- for (int j = 0; j < mesh->totpoly; j++, txface++) {
- CALLBACK_INVOKE(txface->tpage, IDWALK_CB_USER_ONE);
- }
- }
- }
-
- for (i = 0; i < mesh->fdata.totlayer; i++) {
- if (mesh->fdata.layers[i].type == CD_MTFACE) {
- MTFace *tface = (MTFace *)mesh->fdata.layers[i].data;
-
- for (int j = 0; j < mesh->totface; j++, tface++) {
- CALLBACK_INVOKE(tface->tpage, IDWALK_CB_USER_ONE);
- }
- }
- }
- }
break;
}
@@ -681,19 +650,17 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_MA:
{
Material *material = (Material *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (material->mtex[i]) {
- library_foreach_mtex(&data, material->mtex[i]);
- }
- }
if (material->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data);
}
- CALLBACK_INVOKE(material->group, IDWALK_CB_USER);
if (material->texpaintslot != NULL) {
CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
}
+ if (material->gp_style != NULL) {
+ CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER);
+ CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER);
+ }
break;
}
@@ -705,16 +672,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, callback, user_data, flag, &data);
}
CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER);
- if (texture->env) {
- CALLBACK_INVOKE(texture->env->object, IDWALK_CB_NOP);
- CALLBACK_INVOKE(texture->env->ima, IDWALK_CB_USER);
- }
- if (texture->pd)
- CALLBACK_INVOKE(texture->pd->object, IDWALK_CB_NOP);
- if (texture->vd)
- CALLBACK_INVOKE(texture->vd->object, IDWALK_CB_NOP);
- if (texture->ot)
- CALLBACK_INVOKE(texture->ot->object, IDWALK_CB_NOP);
break;
}
@@ -728,11 +685,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_LA:
{
Lamp *lamp = (Lamp *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (lamp->mtex[i]) {
- library_foreach_mtex(&data, lamp->mtex[i]);
- }
- }
if (lamp->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, callback, user_data, flag, &data);
@@ -744,6 +696,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
{
Camera *camera = (Camera *) id;
CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP);
+ for (CameraBGImage *bgpic = camera->bg_images.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->source == CAM_BGIMG_SOURCE_IMAGE) {
+ CALLBACK_INVOKE(bgpic->ima, IDWALK_CB_USER);
+ }
+ else if (bgpic->source == CAM_BGIMG_SOURCE_MOVIE) {
+ CALLBACK_INVOKE(bgpic->clip, IDWALK_CB_USER);
+ }
+ }
+
break;
}
@@ -754,21 +715,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
break;
}
- case ID_SCR:
- {
- bScreen *screen = (bScreen *) id;
- CALLBACK_INVOKE(screen->scene, IDWALK_CB_USER_ONE);
- break;
- }
-
case ID_WO:
{
World *world = (World *) id;
- for (i = 0; i < MAX_MTEX; i++) {
- if (world->mtex[i]) {
- library_foreach_mtex(&data, world->mtex[i]);
- }
- }
if (world->nodetree) {
/* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */
library_foreach_ID_as_subdata_link((ID **)&world->nodetree, callback, user_data, flag, &data);
@@ -783,12 +732,22 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
break;
}
+ case ID_LP:
+ {
+ LightProbe *probe = (LightProbe *) id;
+ CALLBACK_INVOKE(probe->image, IDWALK_CB_USER);
+ CALLBACK_INVOKE(probe->visibility_grp, IDWALK_CB_NOP);
+ break;
+ }
+
case ID_GR:
{
- Group *group = (Group *) id;
- GroupObject *gob;
- for (gob = group->gobject.first; gob; gob = gob->next) {
- CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE);
+ Collection *collection = (Collection *) id;
+ for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
+ }
+ for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ CALLBACK_INVOKE(child->collection, IDWALK_CB_USER);
}
break;
}
@@ -828,6 +787,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
+ if (brush->gpencil_settings) {
+ CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER);
+ }
library_foreach_mtex(&data, &brush->mtex);
library_foreach_mtex(&data, &brush->mask_mtex);
break;
@@ -877,6 +839,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
}
}
+
+ for (ParticleDupliWeight *dw = psett->dupliweights.first; dw; dw = dw->next) {
+ CALLBACK_INVOKE(dw->ob, IDWALK_CB_NOP);
+ }
break;
}
@@ -971,22 +937,60 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
break;
}
+
+ case ID_WM:
+ {
+ wmWindowManager *wm = (wmWindowManager *)id;
+
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook);
+
+ CALLBACK_INVOKE(win->scene, IDWALK_CB_USER_ONE);
+
+ CALLBACK_INVOKE_ID(workspace, IDWALK_CB_NOP);
+ /* allow callback to set a different workspace */
+ BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace);
+ }
+ break;
+ }
+
+ case ID_WS:
+ {
+ WorkSpace *workspace = (WorkSpace *)id;
+ ListBase *layouts = BKE_workspace_layouts_get(workspace);
+
+ for (WorkSpaceLayout *layout = layouts->first; layout; layout = layout->next) {
+ bScreen *screen = BKE_workspace_layout_screen_get(layout);
+
+ /* CALLBACK_INVOKE expects an actual pointer, not a variable holding the pointer.
+ * However we can't access layout->screen here since we are outside the workspace project. */
+ CALLBACK_INVOKE(screen, IDWALK_CB_USER);
+ /* allow callback to set a different screen */
+ BKE_workspace_layout_screen_set(layout, screen);
+ }
+ break;
+ }
case ID_GD:
{
bGPdata *gpencil = (bGPdata *) id;
+ /* materials */
+ for (i = 0; i < gpencil->totcol; i++) {
+ CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
+ }
- for (bGPDlayer *gp_layer = gpencil->layers.first; gp_layer; gp_layer = gp_layer->next) {
- CALLBACK_INVOKE(gp_layer->parent, IDWALK_CB_NOP);
+ for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL; gplayer = gplayer->next) {
+ CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
}
+
break;
}
/* Nothing needed for those... */
+ case ID_SCR:
case ID_IM:
case ID_VF:
case ID_TXT:
case ID_SO:
- case ID_WM:
case ID_PAL:
case ID_PC:
case ID_CF:
@@ -1063,14 +1067,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT,
ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT));
case ID_OB:
- /* Could be the following, but simpler to just always say 'yes' here. */
-#if 0
- return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA, /* obdata */
- ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_PA, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC
- /* + constraints, modifiers and game logic ID types... */);
-#else
+ /* Could be more specific, but simpler to just always say 'yes' here. */
return true;
-#endif
case ID_ME:
return ELEM(id_type_used, ID_ME, ID_KE, ID_MA, ID_IM);
case ID_CU:
@@ -1096,16 +1094,12 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_SPK:
return ELEM(id_type_used, ID_SO);
case ID_GR:
- return ELEM(id_type_used, ID_OB);
+ return ELEM(id_type_used, ID_OB, ID_GR);
case ID_NT:
- /* Could be the following, but node.id has no type restriction... */
-#if 0
- return ELEM(id_type_used, ID_GD /* + node.id types... */);
-#else
+ /* Could be more specific, but node.id has no type restriction... */
return true;
-#endif
case ID_BR:
- return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE);
+ return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE, ID_MA);
case ID_PA:
return ELEM(id_type_used, ID_OB, ID_GR, ID_TE);
case ID_MC:
@@ -1114,13 +1108,18 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */
case ID_LS:
return (ELEM(id_type_used, ID_TE, ID_OB));
+ case ID_LP:
+ return ELEM(id_type_used, ID_IM);
+ case ID_GD:
+ return ELEM(id_type_used, ID_MA);
+ case ID_WS:
+ return ELEM(id_type_used, ID_SCR, ID_SCE);
case ID_IM:
case ID_VF:
case ID_TXT:
case ID_SO:
case ID_AR:
case ID_AC:
- case ID_GD:
case ID_WM:
case ID_PAL:
case ID_PC:
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index f791d9a6591..404028f336e 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -39,7 +39,7 @@
#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_cachefile_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_ipo_types.h"
#include "DNA_key_types.h"
@@ -53,6 +53,7 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
@@ -60,6 +61,7 @@
#include "DNA_text_types.h"
#include "DNA_vfont_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_world_types.h"
#include "BLI_blenlib.h"
@@ -71,11 +73,10 @@
#include "BKE_brush.h"
#include "BKE_camera.h"
#include "BKE_cachefile.h"
+#include "BKE_collection.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_font.h"
-#include "BKE_group.h"
#include "BKE_gpencil.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
@@ -83,7 +84,9 @@
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -99,15 +102,19 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
-#include "BKE_sca.h"
+#include "BKE_lightprobe.h"
#include "BKE_speaker.h"
#include "BKE_sound.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
#include "BKE_text.h"
#include "BKE_texture.h"
+#include "BKE_workspace.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
@@ -173,6 +180,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
if (*id_p && (*id_p == old_id)) {
+ const bool is_reference = (cb_flag & IDWALK_CB_STATIC_OVERRIDE_REFERENCE) != 0;
const bool is_indirect = (cb_flag & IDWALK_CB_INDIRECT_USAGE) != 0;
const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
/* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct,
@@ -183,11 +191,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id));
const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) &&
(id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0);
+ const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_STATIC_OVERRIDE) != 0;
const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0;
#ifdef DEBUG_PRINT
- printf("In %s: Remapping %s (%p) to %s (%p) (is_indirect: %d, skip_indirect: %d)\n",
- id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, is_indirect, skip_indirect);
+ printf("In %s (lib %p): Remapping %s (%p) to %s (%p) "
+ "(is_indirect: %d, skip_indirect: %d, is_reference: %d, skip_reference: %d)\n",
+ id->name, id->lib, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id,
+ is_indirect, skip_indirect, is_reference, skip_reference);
#endif
if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) {
@@ -199,7 +210,8 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
* (skipped_indirect too). */
if ((is_never_null && skip_never_null) ||
(is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) ||
- (skip_indirect && is_indirect))
+ (skip_indirect && is_indirect) ||
+ (is_reference && skip_reference))
{
if (is_indirect) {
id_remap_data->skipped_indirect++;
@@ -212,7 +224,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
}
}
}
- else if (is_never_null || is_obj_editmode) {
+ else if (is_never_null || is_obj_editmode || is_reference) {
id_remap_data->skipped_direct++;
}
else {
@@ -229,7 +241,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
else {
if (!is_never_null) {
*id_p = new_id;
- DAG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update_ex(id_remap_data->bmain, id_self, DEG_TAG_TRANSFORM | DEG_TAG_TIME | DEG_TAG_GEOMETRY);
}
if (cb_flag & IDWALK_CB_USER) {
id_us_min(old_id);
@@ -251,58 +263,9 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id
return IDWALK_RET_NOP;
}
-/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */
-static void libblock_remap_data_preprocess_scene_base_unlink(
- IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect)
-{
- if (skip_indirect && is_indirect) {
- r_id_remap_data->skipped_indirect++;
- r_id_remap_data->skipped_refcounted++;
- }
- else {
- id_us_min((ID *)base->object);
- BKE_scene_base_unlink(sce, base);
- MEM_freeN(base);
- if (!is_indirect) {
- r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT;
- }
- }
-}
-
static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
{
switch (GS(r_id_remap_data->id->name)) {
- case ID_SCE:
- {
- Scene *sce = (Scene *)r_id_remap_data->id;
-
- if (!r_id_remap_data->new_id) {
- const bool is_indirect = (sce->id.lib != NULL);
- const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0;
-
- /* In case we are unlinking... */
- if (!r_id_remap_data->old_id) {
- /* ... everything from scene. */
- Base *base, *base_next;
- for (base = sce->base.first; base; base = base_next) {
- base_next = base->next;
- libblock_remap_data_preprocess_scene_base_unlink(
- r_id_remap_data, sce, base, skip_indirect, is_indirect);
- }
- }
- else if (GS(r_id_remap_data->old_id->name) == ID_OB) {
- /* ... a specific object from scene. */
- Object *old_ob = (Object *)r_id_remap_data->old_id;
- Base *base = BKE_scene_base_find(sce, old_ob);
-
- if (base) {
- libblock_remap_data_preprocess_scene_base_unlink(
- r_id_remap_data, sce, base, skip_indirect, is_indirect);
- }
- }
- }
- break;
- }
case ID_OB:
{
ID *old_id = r_id_remap_data->old_id;
@@ -328,58 +291,49 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
}
}
+/* Can be called with both old_ob and new_ob being NULL, this means we have to check whole Main database then. */
static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, Object *new_ob)
{
- if (old_ob->flag & OB_FROMGROUP) {
- /* Note that for Scene's BaseObject->flag, either we:
- * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already.
- * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is.
- * So in any case, no need to update them here. */
- if (BKE_group_object_find(bmain, NULL, old_ob) == NULL) {
- old_ob->flag &= ~OB_FROMGROUP;
- }
- if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */
- for (Group *group = bmain->group.first; group; group = group->id.next) {
- BKE_group_object_unlink(bmain, group, NULL, NULL, NULL);
+ if (new_ob == NULL) {
+ /* In case we unlinked old_ob (new_ob is NULL), the object has already
+ * been removed from the scenes and their collections. We still have
+ * to remove the NULL children from collections not used in any scene. */
+ BKE_collections_object_remove_nulls(bmain);
+ }
+
+ BKE_main_collection_sync_remap(bmain);
+
+ if (old_ob == NULL) {
+ for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) {
+ if (ob->type == OB_MBALL && BKE_mball_is_basis(ob)) {
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
- else {
- new_ob->flag |= OB_FROMGROUP;
- }
}
- if (old_ob->type == OB_MBALL) {
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
+ else {
+ for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) {
if (ob->type == OB_MBALL && BKE_mball_is_basis_for(ob, old_ob)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ break; /* There is only one basis... */
}
}
}
}
-static void libblock_remap_data_postprocess_group_scene_unlink(Main *bmain, Scene *sce, ID *old_id)
+/* Can be called with both old_collection and new_collection being NULL,
+ * this means we have to check whole Main database then. */
+static void libblock_remap_data_postprocess_collection_update(
+ Main *bmain, Collection *UNUSED(old_collection), Collection *new_collection)
{
- /* Note that here we assume no object has no base (i.e. all objects are assumed instanced
- * in one scene...). */
- for (Base *base = sce->base.first; base; base = base->next) {
- if (base->flag & OB_FROMGROUP) {
- Object *ob = base->object;
-
- if (ob->flag & OB_FROMGROUP) {
- Group *grp = BKE_group_object_find(bmain, NULL, ob);
-
- /* Unlinked group (old_id) is still in bmain... */
- if (grp && (&grp->id == old_id || grp->id.us == 0)) {
- grp = BKE_group_object_find(bmain, grp, ob);
- }
- if (!grp) {
- ob->flag &= ~OB_FROMGROUP;
- }
- }
- if (!(ob->flag & OB_FROMGROUP)) {
- base->flag &= ~OB_FROMGROUP;
- }
- }
+ if (new_collection == NULL) {
+ /* XXX Complex cases can lead to NULL pointers in other collections than old_collection,
+ * and BKE_main_collection_sync_remap() does not tolerate any of those, so for now always check whole
+ * existing collections for NULL pointers.
+ * I'd consider optimizing that whole collection remapping process a TODO for later. */
+ BKE_collections_child_remove_nulls(bmain, NULL /*old_collection*/);
}
+
+ BKE_main_collection_sync_remap(bmain);
}
static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *ob, ID *new_id)
@@ -480,10 +434,6 @@ ATTR_NONNULL(1) static void libblock_remap_data(
}
}
- if (old_id && GS(old_id->name) == ID_OB) {
- BKE_sca_logic_links_remap(bmain, (Object *)old_id, (Object *)new_id);
- }
-
/* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior
* though, we can always add an option (flag) to control this later if needed. */
if (old_id && (old_id->flag & LIB_FAKEUSER)) {
@@ -567,11 +517,7 @@ void BKE_libblock_remap_locked(
libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
break;
case ID_GR:
- if (!new_id) { /* Only affects us in case group was unlinked. */
- for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) {
- libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
- }
- }
+ libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id);
break;
case ID_ME:
case ID_CU:
@@ -594,8 +540,8 @@ void BKE_libblock_remap_locked(
libblock_remap_data_postprocess_nodetree_update(bmain, new_id);
BKE_main_lock(bmain);
- /* Full rebuild of DAG! */
- DAG_relations_tag_update(bmain);
+ /* Full rebuild of DEG! */
+ DEG_relations_tag_update(bmain);
}
void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags)
@@ -668,32 +614,22 @@ void BKE_libblock_relink_ex(
switch (GS(id->name)) {
case ID_SCE:
{
- Scene *sce = (Scene *)id;
-
if (old_id) {
switch (GS(old_id->name)) {
case ID_OB:
- {
libblock_remap_data_postprocess_object_update(bmain, (Object *)old_id, (Object *)new_id);
break;
- }
case ID_GR:
- if (!new_id) { /* Only affects us in case group was unlinked. */
- libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id);
- }
+ libblock_remap_data_postprocess_collection_update(bmain, (Collection *)old_id, (Collection *)new_id);
break;
default:
break;
}
}
else {
- /* No choice but to check whole objects/groups. */
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
- libblock_remap_data_postprocess_object_update(bmain, ob, NULL);
- }
- for (Group *grp = bmain->group.first; grp; grp = grp->id.next) {
- libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL);
- }
+ /* No choice but to check whole objects/collections. */
+ libblock_remap_data_postprocess_collection_update(bmain, NULL, NULL);
+ libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
}
break;
}
@@ -747,6 +683,10 @@ void BKE_libblock_free_data(ID *id, const bool do_id_user)
MEM_freeN(id->properties);
}
+ if (id->override_static) {
+ BKE_override_static_free(&id->override_static);
+ }
+
/* XXX TODO remove animdata handling from each type's freeing func, and do it here, like for copy! */
}
@@ -755,7 +695,7 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
const short type = GS(id->name);
switch (type) {
case ID_SCE:
- BKE_scene_free((Scene *)id);
+ BKE_scene_free_ex((Scene *)id, false);
break;
case ID_LI:
BKE_library_free((Library *)id);
@@ -811,11 +751,14 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
case ID_SPK:
BKE_speaker_free((Speaker *)id);
break;
+ case ID_LP:
+ BKE_lightprobe_free((LightProbe *)id);
+ break;
case ID_SO:
BKE_sound_free((bSound *)id);
break;
case ID_GR:
- BKE_group_free((Group *)id);
+ BKE_collection_free((Collection *)id);
break;
case ID_AR:
BKE_armature_free((bArmature *)id);
@@ -857,6 +800,9 @@ void BKE_libblock_free_datablock(ID *id, const int UNUSED(flag))
case ID_CF:
BKE_cachefile_free((CacheFile *)id);
break;
+ case ID_WS:
+ BKE_workspace_free((WorkSpace *)id);
+ break;
}
}
@@ -867,7 +813,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
if (use_flag_from_idtag) {
if ((id->tag & LIB_TAG_NO_MAIN) != 0) {
- flag |= LIB_ID_FREE_NO_MAIN;
+ flag |= LIB_ID_FREE_NO_MAIN | LIB_ID_FREE_NO_UI_USER | LIB_ID_FREE_NO_DEG_TAG;
}
else {
flag &= ~LIB_ID_FREE_NO_MAIN;
@@ -895,7 +841,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
const short type = GS(id->name);
if (bmain && (flag & LIB_ID_FREE_NO_DEG_TAG) == 0) {
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
}
#ifdef WITH_PYTHON
@@ -958,7 +904,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b
short type = GS(id->name);
ListBase *lb = which_libbase(bmain, type);
- DAG_id_type_tag(bmain, type);
+ DEG_id_type_tag(bmain, type);
#ifdef WITH_PYTHON
#ifdef WITH_PYTHON_SAFETY
@@ -1007,8 +953,8 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
id_us_min(id);
- /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object.
- * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes,
+ /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding collections when deleting an object.
+ * Since only 'user_one' usage of objects is collections, and only 'real user' usage of objects is scenes,
* removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets
* fully unlinked.
* But only for local objects, not linked ones!
diff --git a/source/blender/blenkernel/intern/lightprobe.c b/source/blender/blenkernel/intern/lightprobe.c
new file mode 100644
index 00000000000..4cb2b450afe
--- /dev/null
+++ b/source/blender/blenkernel/intern/lightprobe.c
@@ -0,0 +1,101 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/lightprobe.c
+ * \ingroup bke
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_lightprobe_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_animsys.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_lightprobe.h"
+#include "BKE_main.h"
+
+void BKE_lightprobe_init(LightProbe *probe)
+{
+ BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(probe, id));
+
+ probe->grid_resolution_x = probe->grid_resolution_y = probe->grid_resolution_z = 4;
+ probe->distinf = 2.5f;
+ probe->distpar = 2.5f;
+ probe->falloff = 0.2f;
+ probe->clipsta = 0.8f;
+ probe->clipend = 40.0f;
+ probe->vis_bias = 1.0f;
+ probe->vis_blur = 0.2f;
+ probe->intensity = 1.0f;
+
+ probe->flag = LIGHTPROBE_FLAG_SHOW_INFLUENCE | LIGHTPROBE_FLAG_SHOW_DATA;
+}
+
+void *BKE_lightprobe_add(Main *bmain, const char *name)
+{
+ LightProbe *probe;
+
+ probe = BKE_libblock_alloc(bmain, ID_LP, name, 0);
+
+ BKE_lightprobe_init(probe);
+
+ return probe;
+}
+
+/**
+ * Only copy internal data of LightProbe ID from source to already allocated/initialized destination.
+ * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
+ *
+ * WARNING! This function will not handle ID user count!
+ *
+ * \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
+ */
+void BKE_lightprobe_copy_data(
+ Main *UNUSED(bmain), LightProbe *UNUSED(probe_dst), const LightProbe *UNUSED(probe_src), const int UNUSED(flag))
+{
+ /* Nothing to do here. */
+}
+
+LightProbe *BKE_lightprobe_copy(Main *bmain, const LightProbe *probe)
+{
+ LightProbe *probe_copy;
+ BKE_id_copy_ex(bmain, &probe->id, (ID **)&probe_copy, 0, false);
+ return probe_copy;
+}
+
+void BKE_lightprobe_make_local(Main *bmain, LightProbe *probe, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &probe->id, true, lib_local);
+}
+
+void BKE_lightprobe_free(LightProbe *probe)
+{
+ BKE_animdata_free((ID *)probe, false);
+}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index e00884c8a9d..5757ae7480b 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -212,20 +212,11 @@ void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle,
BKE_id_make_local_generic(bmain, &linestyle->id, true, lib_local);
}
-FreestyleLineStyle *BKE_linestyle_active_from_scene(Scene *scene)
+FreestyleLineStyle *BKE_linestyle_active_from_view_layer(ViewLayer *view_layer)
{
- SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- if (!actsrl) {
- return NULL;
- }
-
- FreestyleConfig *config = &actsrl->freestyleConfig;
+ FreestyleConfig *config = &view_layer->freestyle_config;
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
-
- if (lineset) {
- return lineset->linestyle;
- }
- return NULL;
+ return (lineset) ? lineset->linestyle : NULL;
}
static LineStyleModifier *new_modifier(const char *name, int type, size_t size)
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
new file mode 100644
index 00000000000..6291e35e968
--- /dev/null
+++ b/source/blender/blenkernel/intern/main.c
@@ -0,0 +1,446 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/main.c
+ * \ingroup bke
+ *
+ * Contains management of Main database itself.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_mempool.h"
+#include "BLI_threads.h"
+
+#include "DNA_ID.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_main.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+Main *BKE_main_new(void)
+{
+ Main *bmain = MEM_callocN(sizeof(Main), "new main");
+ bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
+ BLI_spin_init((SpinLock *)bmain->lock);
+ return bmain;
+}
+
+void BKE_main_free(Main *mainvar)
+{
+ /* also call when reading a file, erase all, etc */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+
+ MEM_SAFE_FREE(mainvar->blen_thumb);
+
+ a = set_listbasepointers(mainvar, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id;
+
+ while ( (id = lb->first) ) {
+#if 1
+ BKE_libblock_free_ex(mainvar, id, false, false);
+#else
+ /* errors freeing ID's can be hard to track down,
+ * enable this so valgrind will give the line number in its error log */
+ switch (a) {
+ case 0: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 1: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 2: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 3: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 4: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 5: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 6: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 7: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 8: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 9: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 10: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 11: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 12: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 13: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 14: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 15: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 16: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 17: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 18: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 19: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 20: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 21: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 22: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 23: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 24: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 25: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 26: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 27: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 28: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 29: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 30: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 31: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 32: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 33: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ case 34: BKE_libblock_free_ex(mainvar, id, false, false); break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+#endif
+ }
+ }
+
+ if (mainvar->relations) {
+ BKE_main_relations_free(mainvar);
+ }
+
+ BLI_spin_end((SpinLock *)mainvar->lock);
+ MEM_freeN(mainvar->lock);
+ MEM_freeN(mainvar);
+}
+
+void BKE_main_lock(struct Main *bmain)
+{
+ BLI_spin_lock((SpinLock *) bmain->lock);
+}
+
+void BKE_main_unlock(struct Main *bmain)
+{
+ BLI_spin_unlock((SpinLock *) bmain->lock);
+}
+
+
+static int main_relations_create_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag)
+{
+ MainIDRelations *rel = user_data;
+
+ if (*id_pointer) {
+ MainIDRelationsEntry *entry, **entry_p;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = id_pointer;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+
+ entry = BLI_mempool_alloc(rel->entry_pool);
+ if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) {
+ entry->next = *entry_p;
+ }
+ else {
+ entry->next = NULL;
+ }
+ entry->id_pointer = (ID **)id_self;
+ entry->usage_flag = cb_flag;
+ *entry_p = entry;
+ }
+
+ return IDWALK_RET_NOP;
+}
+
+/** Generate the mappings between used IDs and their users, and vice-versa. */
+void BKE_main_relations_create(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ if (bmain->relations != NULL) {
+ BKE_main_relations_free(bmain);
+ }
+
+ bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__);
+ bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
+ bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP);
+
+ for (a = set_listbasepointers(bmain, lbarray); a--; ) {
+ for (id = lbarray[a]->first; id; id = id->next) {
+ BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY);
+ }
+ }
+}
+
+void BKE_main_relations_free(Main *bmain)
+{
+ if (bmain->relations) {
+ if (bmain->relations->id_used_to_user) {
+ BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL);
+ }
+ if (bmain->relations->id_user_to_used) {
+ BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL);
+ }
+ BLI_mempool_destroy(bmain->relations->entry_pool);
+ MEM_freeN(bmain->relations);
+ bmain->relations = NULL;
+ }
+}
+
+/**
+ * Generates a raw .blend file thumbnail data from given image.
+ *
+ * \param bmain If not NULL, also store generated data in this Main.
+ * \param img ImBuf image to generate thumbnail data from.
+ * \return The generated .blend file raw thumbnail data.
+ */
+BlendThumbnail *BKE_main_thumbnail_from_imbuf(Main *bmain, ImBuf *img)
+{
+ BlendThumbnail *data = NULL;
+
+ if (bmain) {
+ MEM_SAFE_FREE(bmain->blen_thumb);
+ }
+
+ if (img) {
+ const size_t sz = BLEN_THUMB_MEMSIZE(img->x, img->y);
+ data = MEM_mallocN(sz, __func__);
+
+ IMB_rect_from_float(img); /* Just in case... */
+ data->width = img->x;
+ data->height = img->y;
+ memcpy(data->rect, img->rect, sz - sizeof(*data));
+ }
+
+ if (bmain) {
+ bmain->blen_thumb = data;
+ }
+ return data;
+}
+
+/**
+ * Generates an image from raw .blend file thumbnail \a data.
+ *
+ * \param bmain Use this bmain->blen_thumb data if given \a data is NULL.
+ * \param data Raw .blend file thumbnail data.
+ * \return An ImBuf from given data, or NULL if invalid.
+ */
+ImBuf *BKE_main_thumbnail_to_imbuf(Main *bmain, BlendThumbnail *data)
+{
+ ImBuf *img = NULL;
+
+ if (!data && bmain) {
+ data = bmain->blen_thumb;
+ }
+
+ if (data) {
+ /* Note: we cannot use IMB_allocFromBuffer(), since it tries to dupalloc passed buffer, which will fail
+ * here (we do not want to pass the first two ints!). */
+ img = IMB_allocImBuf((unsigned int)data->width, (unsigned int)data->height, 32, IB_rect | IB_metadata);
+ memcpy(img->rect, data->rect, BLEN_THUMB_MEMSIZE(data->width, data->height) - sizeof(*data));
+ }
+
+ return img;
+}
+
+/**
+ * Generates an empty (black) thumbnail for given Main.
+ */
+void BKE_main_thumbnail_create(struct Main *bmain)
+{
+ MEM_SAFE_FREE(bmain->blen_thumb);
+
+ bmain->blen_thumb = MEM_callocN(BLEN_THUMB_MEMSIZE(BLEN_THUMB_SIZE, BLEN_THUMB_SIZE), __func__);
+ bmain->blen_thumb->width = BLEN_THUMB_SIZE;
+ bmain->blen_thumb->height = BLEN_THUMB_SIZE;
+}
+
+/**
+ * Return filepath of given \a main.
+ */
+const char *BKE_main_blendfile_path(const Main *bmain)
+{
+ return bmain->name;
+}
+
+/**
+ * Return filepath of global main (G_MAIN).
+ *
+ * \warning Usage is not recommended, you should always try to get a valid Main pointer from context...
+ */
+const char *BKE_main_blendfile_path_from_global(void)
+{
+ return BKE_main_blendfile_path(G_MAIN);
+}
+
+/**
+ * \return A pointer to the \a ListBase of given \a bmain for requested \a type ID type.
+ */
+ListBase *which_libbase(Main *bmain, short type)
+{
+ switch ((ID_Type)type) {
+ case ID_SCE:
+ return &(bmain->scene);
+ case ID_LI:
+ return &(bmain->library);
+ case ID_OB:
+ return &(bmain->object);
+ case ID_ME:
+ return &(bmain->mesh);
+ case ID_CU:
+ return &(bmain->curve);
+ case ID_MB:
+ return &(bmain->mball);
+ case ID_MA:
+ return &(bmain->mat);
+ case ID_TE:
+ return &(bmain->tex);
+ case ID_IM:
+ return &(bmain->image);
+ case ID_LT:
+ return &(bmain->latt);
+ case ID_LA:
+ return &(bmain->lamp);
+ case ID_CA:
+ return &(bmain->camera);
+ case ID_IP:
+ return &(bmain->ipo);
+ case ID_KE:
+ return &(bmain->key);
+ case ID_WO:
+ return &(bmain->world);
+ case ID_SCR:
+ return &(bmain->screen);
+ case ID_VF:
+ return &(bmain->vfont);
+ case ID_TXT:
+ return &(bmain->text);
+ case ID_SPK:
+ return &(bmain->speaker);
+ case ID_LP:
+ return &(bmain->lightprobe);
+ case ID_SO:
+ return &(bmain->sound);
+ case ID_GR:
+ return &(bmain->collection);
+ case ID_AR:
+ return &(bmain->armature);
+ case ID_AC:
+ return &(bmain->action);
+ case ID_NT:
+ return &(bmain->nodetree);
+ case ID_BR:
+ return &(bmain->brush);
+ case ID_PA:
+ return &(bmain->particle);
+ case ID_WM:
+ return &(bmain->wm);
+ case ID_GD:
+ return &(bmain->gpencil);
+ case ID_MC:
+ return &(bmain->movieclip);
+ case ID_MSK:
+ return &(bmain->mask);
+ case ID_LS:
+ return &(bmain->linestyle);
+ case ID_PAL:
+ return &(bmain->palettes);
+ case ID_PC:
+ return &(bmain->paintcurves);
+ case ID_CF:
+ return &(bmain->cachefiles);
+ case ID_WS:
+ return &(bmain->workspaces);
+ }
+ return NULL;
+}
+
+/**
+ * puts into array *lb pointers to all the ListBase structs in main,
+ * and returns the number of them as the function result. This is useful for
+ * generic traversal of all the blocks in a Main (by traversing all the
+ * lists in turn), without worrying about block types.
+ *
+ * \note MAX_LIBARRAY define should match this code */
+int set_listbasepointers(Main *bmain, ListBase **lb)
+{
+ /* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last.
+ * This is important because freeing data decreases usercounts of other datablocks,
+ * if this data is its self freed it can crash. */
+ lb[INDEX_ID_LI] = &(bmain->library); /* Libraries may be accessed from pretty much any other ID... */
+ lb[INDEX_ID_IP] = &(bmain->ipo);
+ lb[INDEX_ID_AC] = &(bmain->action); /* moved here to avoid problems when freeing with animato (aligorith) */
+ lb[INDEX_ID_KE] = &(bmain->key);
+ lb[INDEX_ID_PAL] = &(bmain->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */
+ lb[INDEX_ID_GD] = &(bmain->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
+ lb[INDEX_ID_NT] = &(bmain->nodetree);
+ lb[INDEX_ID_IM] = &(bmain->image);
+ lb[INDEX_ID_TE] = &(bmain->tex);
+ lb[INDEX_ID_MA] = &(bmain->mat);
+ lb[INDEX_ID_VF] = &(bmain->vfont);
+
+ /* Important!: When adding a new object type,
+ * the specific data should be inserted here
+ */
+
+ lb[INDEX_ID_AR] = &(bmain->armature);
+
+ lb[INDEX_ID_CF] = &(bmain->cachefiles);
+ lb[INDEX_ID_ME] = &(bmain->mesh);
+ lb[INDEX_ID_CU] = &(bmain->curve);
+ lb[INDEX_ID_MB] = &(bmain->mball);
+
+ lb[INDEX_ID_LT] = &(bmain->latt);
+ lb[INDEX_ID_LA] = &(bmain->lamp);
+ lb[INDEX_ID_CA] = &(bmain->camera);
+
+ lb[INDEX_ID_TXT] = &(bmain->text);
+ lb[INDEX_ID_SO] = &(bmain->sound);
+ lb[INDEX_ID_GR] = &(bmain->collection);
+ lb[INDEX_ID_PAL] = &(bmain->palettes);
+ lb[INDEX_ID_PC] = &(bmain->paintcurves);
+ lb[INDEX_ID_BR] = &(bmain->brush);
+ lb[INDEX_ID_PA] = &(bmain->particle);
+ lb[INDEX_ID_SPK] = &(bmain->speaker);
+ lb[INDEX_ID_LP] = &(bmain->lightprobe);
+
+ lb[INDEX_ID_WO] = &(bmain->world);
+ lb[INDEX_ID_MC] = &(bmain->movieclip);
+ lb[INDEX_ID_SCR] = &(bmain->screen);
+ lb[INDEX_ID_OB] = &(bmain->object);
+ lb[INDEX_ID_LS] = &(bmain->linestyle); /* referenced by scenes */
+ lb[INDEX_ID_SCE] = &(bmain->scene);
+ lb[INDEX_ID_WS] = &(bmain->workspaces); /* before wm, so it's freed after it! */
+ lb[INDEX_ID_WM] = &(bmain->wm);
+ lb[INDEX_ID_MSK] = &(bmain->mask);
+
+ lb[INDEX_ID_NULL] = NULL;
+
+ return (MAX_LIBARRAY - 1);
+}
+
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index b5742dbdbb7..97058467fd9 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -51,7 +51,7 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
+
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mask.h"
@@ -61,6 +61,8 @@
#include "BKE_movieclip.h"
#include "BKE_image.h"
+#include "DEG_depsgraph_build.h"
+
static struct {
ListBase splines;
struct GHash *id_hash;
@@ -817,7 +819,7 @@ Mask *BKE_mask_new(Main *bmain, const char *name)
mask->sfra = 1;
mask->efra = 100;
- DAG_relations_tag_update(bmain);
+ DEG_relations_tag_update(bmain);
return mask;
}
@@ -1417,34 +1419,6 @@ void BKE_mask_evaluate(Mask *mask, const float ctime, const bool do_newframe)
* for now re-evaluate all. eventually this might work differently */
void BKE_mask_update_display(Mask *mask, float ctime)
{
-#if 0
- MaskLayer *masklay;
-
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- if (spline->points_deform) {
- int i = 0;
-
- for (i = 0; i < spline->tot_point; i++) {
- MaskSplinePoint *point;
-
- if (spline->points_deform) {
- point = &spline->points_deform[i];
- BKE_mask_point_free(point);
- }
- }
- if (spline->points_deform) {
- MEM_freeN(spline->points_deform);
- }
-
- spline->points_deform = NULL;
- }
- }
- }
-#endif
-
BKE_mask_evaluate(mask, ctime, false);
}
@@ -1457,18 +1431,6 @@ void BKE_mask_evaluate_all_masks(Main *bmain, float ctime, const bool do_newfram
}
}
-void BKE_mask_update_scene(Main *bmain, Scene *scene)
-{
- Mask *mask;
-
- for (mask = bmain->mask.first; mask; mask = mask->id.next) {
- if (mask->id.recalc & ID_RECALC_ALL) {
- bool do_new_frame = (mask->id.recalc & ID_RECALC_DATA) != 0;
- BKE_mask_evaluate_all_masks(bmain, CFRA, do_new_frame);
- }
- }
-}
-
void BKE_mask_parent_init(MaskParent *parent)
{
parent->id_type = ID_MC;
@@ -1667,19 +1629,6 @@ MaskLayerShape *BKE_mask_layer_shape_verify_frame(MaskLayer *masklay, const int
BKE_mask_layer_shape_sort(masklay);
}
-#if 0
- {
- MaskLayerShape *masklay_shape;
- int i = 0;
- for (masklay_shape = masklay->splines_shapes.first;
- masklay_shape;
- masklay_shape = masklay_shape->next)
- {
- printf("mask %d, %d\n", i++, masklay_shape->frame);
- }
- }
-#endif
-
return masklay_shape;
}
diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c
index e2a9691e577..55939f8eadf 100644
--- a/source/blender/blenkernel/intern/mask_evaluate.c
+++ b/source/blender/blenkernel/intern/mask_evaluate.c
@@ -40,12 +40,13 @@
#include "BLI_math.h"
#include "DNA_mask_types.h"
+#include "DNA_object_types.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_mask.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height)
{
@@ -897,24 +898,26 @@ void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime)
}
}
-void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask)
+void BKE_mask_eval_animation(struct Depsgraph *depsgraph, Mask *mask)
{
- DEG_debug_print_eval(__func__, mask->id.name, mask);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
for (MaskLayer *mask_layer = mask->masklayers.first;
mask_layer != NULL;
mask_layer = mask_layer->next)
{
- BKE_mask_layer_evaluate_animation(mask_layer, eval_ctx->ctime);
+ BKE_mask_layer_evaluate_animation(mask_layer, ctime);
}
}
-void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask)
+void BKE_mask_eval_update(struct Depsgraph *depsgraph, Mask *mask)
{
- DEG_debug_print_eval(__func__, mask->id.name, mask);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval(depsgraph, __func__, mask->id.name, mask);
for (MaskLayer *mask_layer = mask->masklayers.first;
mask_layer != NULL;
mask_layer = mask_layer->next)
{
- BKE_mask_layer_evaluate_deform(mask_layer, eval_ctx->ctime);
+ BKE_mask_layer_evaluate_deform(mask_layer, ctime);
}
}
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 2f2b82a00eb..ecdd30edc36 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -749,12 +749,6 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas
for (j = 0; j < tot_diff_feather_points; j++) {
copy_v2_v2(co_feather, diff_feather_points[j]);
sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
-
- /* no need for these attrs */
-#if 0
- sf_vert->tmp.u = sf_vert_tot;
- sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
-#endif
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
}
@@ -1217,7 +1211,6 @@ static float maskrasterize_layer_z_depth_tri(const float pt[2],
}
#endif
-#if 1
static float maskrasterize_layer_z_depth_quad(const float pt[2],
const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{
@@ -1226,7 +1219,6 @@ static float maskrasterize_layer_z_depth_quad(const float pt[2],
//return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]) + (v4[2] * w[3]);
return w[2] + w[3]; /* we can make this assumption for small speedup */
}
-#endif
static float maskrasterize_layer_isect(unsigned int *face, float (*cos)[3], const float dist_orig, const float xy[2])
{
@@ -1247,10 +1239,8 @@ static float maskrasterize_layer_isect(unsigned int *face, float (*cos)[3], cons
}
#else
/* we know all tris are close for now */
- if (1) {
- if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
- return 0.0f;
- }
+ if (isect_point_tri_v2_cw(xy, cos[face[0]], cos[face[1]], cos[face[2]])) {
+ return 0.0f;
}
#endif
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 1caef98ea11..6c13a7d3729 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -37,12 +37,13 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_customdata_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_ID.h"
#include "DNA_meta_types.h"
#include "DNA_node_types.h"
@@ -56,9 +57,10 @@
#include "BLI_array_utils.h"
#include "BKE_animsys.h"
+#include "BKE_brush.h"
#include "BKE_displist.h"
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
+#include "BKE_gpencil.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
@@ -73,6 +75,9 @@
#include "BKE_editmesh.h"
#include "BKE_font.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
#include "GPU_material.h"
/* used in UI and render */
@@ -87,16 +92,10 @@ void init_def_material(void)
/** Free (or release) any data used by this material (does not free the material itself). */
void BKE_material_free(Material *ma)
{
- int a;
-
BKE_animdata_free((ID *)ma, false);
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(ma->mtex[a]);
- }
-
- MEM_SAFE_FREE(ma->ramp_col);
- MEM_SAFE_FREE(ma->ramp_spec);
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
/* is no lib link block, but material extension */
if (ma->nodetree) {
@@ -107,105 +106,51 @@ void BKE_material_free(Material *ma)
MEM_SAFE_FREE(ma->texpaintslot);
- GPU_material_free(&ma->gpumaterial);
+ MEM_SAFE_FREE(ma->gp_style);
BKE_icon_id_delete((ID *)ma);
BKE_previewimg_free(&ma->preview);
}
+void BKE_material_init_gpencil_settings(Material *ma)
+{
+ if ((ma) && (ma->gp_style == NULL)) {
+ ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings");
+
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* set basic settings */
+ gp_style->stroke_rgba[3] = 1.0f;
+ gp_style->pattern_gridsize = 0.1f;
+ gp_style->gradient_radius = 0.5f;
+ ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
+ ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
+ ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
+ gp_style->texture_opacity = 1.0f;
+ gp_style->texture_pixsize = 100.0f;
+
+ gp_style->flag |= GP_STYLE_STROKE_SHOW;
+ gp_style->flag |= GP_STYLE_FILL_SHOW;
+ }
+}
+
void BKE_material_init(Material *ma)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id));
- ma->r = ma->g = ma->b = ma->ref = 0.8;
+ ma->r = ma->g = ma->b = 0.8;
ma->specr = ma->specg = ma->specb = 1.0;
- ma->mirr = ma->mirg = ma->mirb = 1.0;
- ma->spectra = 1.0;
- ma->amb = 1.0;
- ma->alpha = 1.0;
- ma->spec = ma->hasize = 0.5;
- ma->har = 50;
- ma->starc = ma->ringc = 4;
- ma->linec = 12;
- ma->flarec = 1;
- ma->flaresize = ma->subsize = 1.0;
- ma->flareboost = 1;
- ma->seed2 = 6;
- ma->friction = 0.5;
- ma->refrac = 4.0;
- ma->roughness = 0.5;
- ma->param[0] = 0.5;
- ma->param[1] = 0.1;
- ma->param[2] = 0.5;
- ma->param[3] = 0.1;
- ma->rms = 0.1;
- ma->darkness = 1.0;
-
- ma->strand_sta = ma->strand_end = 1.0f;
-
- ma->ang = 1.0;
- ma->ray_depth = 2;
- ma->ray_depth_tra = 2;
- ma->fresnel_mir = 0.0;
- ma->fresnel_tra = 0.0;
- ma->fresnel_tra_i = 1.25;
- ma->fresnel_mir_i = 1.25;
- ma->tx_limit = 0.0;
- ma->tx_falloff = 1.0;
- ma->shad_alpha = 1.0f;
- ma->vcol_alpha = 0;
-
- ma->gloss_mir = ma->gloss_tra = 1.0;
- ma->samp_gloss_mir = ma->samp_gloss_tra = 18;
- ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005;
- ma->dist_mir = 0.0;
- ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
-
- ma->rampfac_col = 1.0;
- ma->rampfac_spec = 1.0;
+ // ma->alpha = 1.0; /* DEPRECATED */
+ ma->spec = 0.5;
+
+ ma->roughness = 0.25f;
+
ma->pr_lamp = 3; /* two lamps, is bits */
ma->pr_type = MA_SPHERE;
- ma->sss_radius[0] = 1.0f;
- ma->sss_radius[1] = 1.0f;
- ma->sss_radius[2] = 1.0f;
- ma->sss_col[0] = 1.0f;
- ma->sss_col[1] = 1.0f;
- ma->sss_col[2] = 1.0f;
- ma->sss_error = 0.05f;
- ma->sss_scale = 0.1f;
- ma->sss_ior = 1.3f;
- ma->sss_colfac = 1.0f;
- ma->sss_texfac = 0.0f;
- ma->sss_front = 1.0f;
- ma->sss_back = 1.0f;
-
- ma->vol.density = 1.0f;
- ma->vol.emission = 0.0f;
- ma->vol.scattering = 1.0f;
- ma->vol.reflection = 1.0f;
- ma->vol.transmission_col[0] = ma->vol.transmission_col[1] = ma->vol.transmission_col[2] = 1.0f;
- ma->vol.reflection_col[0] = ma->vol.reflection_col[1] = ma->vol.reflection_col[2] = 1.0f;
- ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f;
- ma->vol.density_scale = 1.0f;
- ma->vol.depth_cutoff = 0.01f;
- ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED;
- ma->vol.stepsize = 0.2f;
- ma->vol.shade_type = MA_VOL_SHADE_SHADED;
- ma->vol.shadeflag |= MA_VOL_PRECACHESHADING;
- ma->vol.precache_resolution = 50;
- ma->vol.ms_spread = 0.2f;
- ma->vol.ms_diff = 1.f;
- ma->vol.ms_intensity = 1.f;
-
- ma->game.flag = GEMAT_BACKCULL;
- ma->game.alpha_blend = 0;
- ma->game.face_orientation = 0;
-
- ma->mode = MA_TRACEBLE | MA_SHADBUF | MA_SHADOW | MA_RAYBIAS | MA_TANGENT_STR | MA_ZTRANSP;
- ma->mode2 = MA_CASTSHADOW;
- ma->shade_flag = MA_APPROX_OCCLUSION;
ma->preview = NULL;
+
+ ma->alpha_threshold = 0.5f;
+
}
Material *BKE_material_add(Main *bmain, const char *name)
@@ -219,6 +164,21 @@ Material *BKE_material_add(Main *bmain, const char *name)
return ma;
}
+Material *BKE_material_add_gpencil(Main *bmain, const char *name)
+{
+ Material *ma;
+
+ ma = BKE_material_add(bmain, name);
+
+ /* grease pencil settings */
+ if (ma != NULL) {
+ BKE_material_init_gpencil_settings(ma);
+ BKE_brush_update_material(bmain, ma, NULL);
+ }
+ return ma;
+}
+
+
/**
* Only copy internal data of Material ID from source to already allocated/initialized destination.
* You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
@@ -229,20 +189,6 @@ Material *BKE_material_add(Main *bmain, const char *name)
*/
void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag)
{
- for (int a = 0; a < MAX_MTEX; a++) {
- if (ma_src->mtex[a]) {
- ma_dst->mtex[a] = MEM_mallocN(sizeof(*ma_dst->mtex[a]), __func__);
- *ma_dst->mtex[a] = *ma_src->mtex[a];
- }
- }
-
- if (ma_src->ramp_col) {
- ma_dst->ramp_col = MEM_dupallocN(ma_src->ramp_col);
- }
- if (ma_src->ramp_spec) {
- ma_dst->ramp_spec = MEM_dupallocN(ma_src->ramp_spec);
- }
-
if (ma_src->nodetree) {
/* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
* (see BKE_libblock_copy_ex()). */
@@ -260,7 +206,13 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr
ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot);
}
+ if (ma_src->gp_style != NULL) {
+ ma_dst->gp_style = MEM_dupallocN(ma_src->gp_style);
+ }
+
BLI_listbase_clear(&ma_dst->gpumaterial);
+
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
}
Material *BKE_material_copy(Main *bmain, const Material *ma)
@@ -281,29 +233,25 @@ Material *BKE_material_localize(Material *ma)
* ... Once f*** nodes are fully converted to that too :( */
Material *man;
- int a;
-
- man = BKE_libblock_copy_nolib(&ma->id, false);
- /* no increment for texture ID users, in previewrender.c it prevents decrement */
- for (a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a]) {
- man->mtex[a] = MEM_mallocN(sizeof(MTex), "copymaterial");
- memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex));
- }
- }
-
- if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col);
- if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec);
+ BKE_id_copy_ex(
+ NULL, &ma->id, (ID **)&man,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_COPY_NO_PREVIEW |
+ LIB_ID_COPY_NO_ANIMDATA),
+ false);
man->texpaintslot = NULL;
man->preview = NULL;
- if (ma->nodetree)
- man->nodetree = ntreeLocalize(ma->nodetree);
-
+ /* man->gp_style = NULL; */ /* XXX: We probably don't want to clear here, or else we may get problems with COW later? */
BLI_listbase_clear(&man->gpumaterial);
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
+
+ man->id.tag |= LIB_TAG_LOCALIZED;
+
return man;
}
@@ -317,6 +265,7 @@ Material ***give_matarar(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
+ bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@@ -330,6 +279,10 @@ Material ***give_matarar(Object *ob)
mb = ob->data;
return &(mb->mat);
}
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->mat);
+ }
return NULL;
}
@@ -338,6 +291,7 @@ short *give_totcolp(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
+ bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@@ -351,6 +305,10 @@ short *give_totcolp(Object *ob)
mb = ob->data;
return &(mb->totcol);
}
+ else if (ob->type == OB_GPENCIL) {
+ gpd = ob->data;
+ return &(gpd->totcol);
+ }
return NULL;
}
@@ -367,6 +325,8 @@ Material ***give_matarar_id(ID *id)
return &(((Curve *)id)->mat);
case ID_MB:
return &(((MetaBall *)id)->mat);
+ case ID_GD:
+ return &(((bGPdata *)id)->mat);
default:
break;
}
@@ -385,6 +345,8 @@ short *give_totcolp_id(ID *id)
return &(((Curve *)id)->totcol);
case ID_MB:
return &(((MetaBall *)id)->totcol);
+ case ID_GD:
+ return &(((bGPdata *)id)->totcol);
default:
break;
}
@@ -406,6 +368,9 @@ static void material_data_index_remove_id(ID *id, short index)
case ID_MB:
/* meta-elems don't have materials atm */
break;
+ case ID_GD:
+ BKE_gpencil_material_index_remove((bGPdata *)id, index);
+ break;
default:
break;
}
@@ -458,7 +423,8 @@ void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user)
}
*totcolp = totcol;
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
@@ -475,7 +441,9 @@ void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
id_us_plus((ID *)ma);
test_all_objects_materials(bmain, id);
- DAG_relations_tag_update(bmain);
+
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
@@ -509,7 +477,8 @@ Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data
material_data_index_remove_id(id, index);
}
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
@@ -536,7 +505,8 @@ void BKE_material_clear_id(Main *bmain, ID *id, bool update_data)
material_data_index_clear_id(id);
}
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
}
}
@@ -581,6 +551,21 @@ Material *give_current_material(Object *ob, short act)
return ma;
}
+MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
+{
+ Material *ma = give_current_material(ob, act);
+ if (ma != NULL) {
+ if (ma->gp_style == NULL) {
+ BKE_material_init_gpencil_settings(ma);
+ }
+
+ return ma->gp_style;
+ }
+ else {
+ return NULL;
+ }
+}
+
Material *give_node_material(Material *ma)
{
if (ma && ma->use_nodes && ma->nodetree) {
@@ -631,7 +616,8 @@ void BKE_material_resize_object(Main *bmain, Object *ob, const short totcol, boo
if (ob->totcol && ob->actcol == 0) ob->actcol = 1;
if (ob->actcol > ob->totcol) ob->actcol = ob->totcol;
- DAG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_GEOMETRY);
+ DEG_relations_tag_update(bmain);
}
void test_object_materials(Main *bmain, Object *ob, ID *id)
@@ -673,14 +659,6 @@ void assign_material_id(Main *bmain, ID *id, Material *ma, short act)
if (act > MAXMAT) return;
if (act < 1) act = 1;
- /* this is needed for Python overrides,
- * we just have to take care that the UI can't do this */
-#if 0
- /* prevent crashing when using accidentally */
- BLI_assert(id->lib == NULL);
- if (id->lib) return;
-#endif
-
/* test arraylens */
totcolp = give_totcolp_id(id);
@@ -820,6 +798,9 @@ void BKE_material_remap_object(Object *ob, const unsigned int *remap)
else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_curve_material_remap(ob->data, remap, ob->totcol);
}
+ else if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_material_remap(ob->data, remap, ob->totcol);
+ }
else {
/* add support for this object data! */
BLI_assert(matar == NULL);
@@ -936,278 +917,8 @@ bool BKE_object_material_slot_add(Main *bmain, Object *ob)
return true;
}
-static void do_init_render_material(Main *bmain, Material *ma, int r_mode, float *amb)
-{
- MTex *mtex;
- int a, needuv = 0, needtang = 0;
-
- if (ma->flarec == 0) ma->flarec = 1;
-
- /* add all texcoflags from mtex, texco and mapto were cleared in advance */
- for (a = 0; a < MAX_MTEX; a++) {
-
- /* separate tex switching */
- if (ma->septex & (1 << a)) continue;
-
- mtex = ma->mtex[a];
- if (mtex && mtex->tex && (mtex->tex->type | (mtex->tex->use_nodes && mtex->tex->nodetree) )) {
-
- ma->texco |= mtex->texco;
- ma->mapto |= mtex->mapto;
-
- /* always get derivatives for these textures */
- if (ELEM(mtex->tex->type, TEX_IMAGE, TEX_ENVMAP)) ma->texco |= TEXCO_OSA;
- else if (mtex->texflag & (MTEX_COMPAT_BUMP | MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)) ma->texco |= TEXCO_OSA;
-
- if (ma->texco & (TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM | TEXCO_STRAND | TEXCO_STRESS)) needuv = 1;
- else if (ma->texco & (TEXCO_GLOB | TEXCO_UV | TEXCO_OBJECT | TEXCO_SPEED)) needuv = 1;
- else if (ma->texco & (TEXCO_LAVECTOR | TEXCO_VIEW)) needuv = 1;
-
- if ((ma->mapto & MAP_NORM) && (mtex->normapspace == MTEX_NSPACE_TANGENT))
- needtang = 1;
- }
- }
-
- if (needtang) ma->mode |= MA_NORMAP_TANG;
- else ma->mode &= ~MA_NORMAP_TANG;
-
- if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) {
- needuv = 1;
- if (r_mode & R_OSA) ma->texco |= TEXCO_OSA; /* for texfaces */
- }
- if (needuv) ma->texco |= NEED_UV;
-
- /* since the raytracer doesnt recalc O structs for each ray, we have to preset them all */
- if (r_mode & R_RAYTRACE) {
- if ((ma->mode & (MA_RAYMIRROR | MA_SHADOW_TRA)) || ((ma->mode & MA_TRANSP) && (ma->mode & MA_RAYTRANSP))) {
- ma->texco |= NEED_UV | TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM;
- if (r_mode & R_OSA) ma->texco |= TEXCO_OSA;
- }
- }
-
- if (amb) {
- ma->ambr = ma->amb * amb[0];
- ma->ambg = ma->amb * amb[1];
- ma->ambb = ma->amb * amb[2];
- }
-
- /* local group override */
- if ((ma->shade_flag & MA_GROUP_LOCAL) && ma->id.lib && ma->group && ma->group->id.lib) {
- Group *group;
-
- for (group = bmain->group.first; group; group = group->id.next) {
- if (!ID_IS_LINKED(group) && STREQ(group->id.name, ma->group->id.name)) {
- ma->group = group;
- }
- }
- }
-}
-
-static void init_render_nodetree(Main *bmain, bNodeTree *ntree, Material *basemat, int r_mode, float *amb)
-{
- bNode *node;
-
- /* parses the geom+tex nodes */
- ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name) == ID_MA) {
- Material *ma = (Material *)node->id;
- if (ma != basemat) {
- do_init_render_material(bmain, ma, r_mode, amb);
- basemat->texco |= ma->texco;
- }
-
- basemat->mode_l |= ma->mode & ~(MA_MODE_PIPELINE | MA_SHLESS);
- basemat->mode2_l |= ma->mode2 & ~MA_MODE2_PIPELINE;
- /* basemat only considered shadeless if all node materials are too */
- if (!(ma->mode & MA_SHLESS))
- basemat->mode_l &= ~MA_SHLESS;
-
- if (ma->strand_surfnor > 0.0f)
- basemat->mode_l |= MA_STR_SURFDIFF;
- }
- else if (node->type == NODE_GROUP)
- init_render_nodetree(bmain, (bNodeTree *)node->id, basemat, r_mode, amb);
- }
- else if (node->typeinfo->type == SH_NODE_NORMAL_MAP) {
- basemat->mode2_l |= MA_TANGENT_CONCRETE;
- NodeShaderNormalMap *nm = node->storage;
- bool taken_into_account = false;
- for (int i = 0; i < basemat->nmap_tangent_names_count; i++) {
- if (STREQ(basemat->nmap_tangent_names[i], nm->uv_map)) {
- taken_into_account = true;
- break;
- }
- }
- if (!taken_into_account) {
- BLI_assert(basemat->nmap_tangent_names_count < MAX_MTFACE + 1);
- strcpy(basemat->nmap_tangent_names[basemat->nmap_tangent_names_count++], nm->uv_map);
- }
- }
- }
-}
-
-void init_render_material(Main *bmain, Material *mat, int r_mode, float *amb)
-{
-
- do_init_render_material(bmain, mat, r_mode, amb);
-
- if (mat->nodetree && mat->use_nodes) {
- /* mode_l will take the pipeline options from the main material, and the or-ed
- * result of non-pipeline options from the nodes. shadeless is an exception,
- * mode_l will have it set when all node materials are shadeless. */
- mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS;
- mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE;
- mat->nmap_tangent_names_count = 0;
- init_render_nodetree(bmain, mat->nodetree, mat, r_mode, amb);
-
- if (!mat->nodetree->execdata)
- mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree);
- }
- else {
- mat->mode_l = mat->mode;
- mat->mode2_l = mat->mode2;
-
- if (mat->strand_surfnor > 0.0f)
- mat->mode_l |= MA_STR_SURFDIFF;
- }
-}
-
-void init_render_materials(Main *bmain, int r_mode, float *amb, bool do_default_material)
-{
- Material *ma;
-
- /* clear these flags before going over materials, to make sure they
- * are cleared only once, otherwise node materials contained in other
- * node materials can go wrong */
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- if (ma->id.us) {
- ma->texco = 0;
- ma->mapto = 0;
- }
- }
-
- /* two steps, first initialize, then or the flags for layers */
- for (ma = bmain->mat.first; ma; ma = ma->id.next) {
- /* is_used flag comes back in convertblender.c */
- ma->flag &= ~MA_IS_USED;
- if (ma->id.us)
- init_render_material(bmain, ma, r_mode, amb);
- }
-
- if (do_default_material) {
- init_render_material(bmain, &defmaterial, r_mode, amb);
- }
-}
-
-/* only needed for nodes now */
-void end_render_material(Material *mat)
-{
- if (mat && mat->nodetree && mat->use_nodes) {
- if (mat->nodetree->execdata)
- ntreeShaderEndExecTree(mat->nodetree->execdata);
- }
-}
-
-void end_render_materials(Main *bmain)
-{
- Material *ma;
- for (ma = bmain->mat.first; ma; ma = ma->id.next)
- if (ma->id.us)
- end_render_material(ma);
-}
-
-static bool material_in_nodetree(bNodeTree *ntree, Material *mat)
-{
- bNode *node;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name) == ID_MA) {
- if (node->id == (ID *)mat) {
- return true;
- }
- }
- else if (node->type == NODE_GROUP) {
- if (material_in_nodetree((bNodeTree *)node->id, mat)) {
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-bool material_in_material(Material *parmat, Material *mat)
-{
- if (parmat == mat)
- return true;
- else if (parmat->nodetree && parmat->use_nodes)
- return material_in_nodetree(parmat->nodetree, mat);
- else
- return false;
-}
-
-
/* ****************** */
-/* Update drivers for materials in a nodetree */
-static void material_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime)
-{
- bNode *node;
-
- /* nodetree itself */
- if (ntree->adt && ntree->adt->drivers.first) {
- BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* nodes */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->id) {
- if (GS(node->id->name) == ID_MA) {
- material_drivers_update(scene, (Material *)node->id, ctime);
- }
- else if (node->type == NODE_GROUP) {
- material_node_drivers_update(scene, (bNodeTree *)node->id, ctime);
- }
- }
- }
-}
-
-/* Calculate all drivers for materials
- * FIXME: this is really a terrible method which may result in some things being calculated
- * multiple times. However, without proper despgraph support for these things, we are forced
- * into this sort of thing...
- */
-void material_drivers_update(Scene *scene, Material *ma, float ctime)
-{
- //if (G.f & G_DEBUG)
- // printf("material_drivers_update(%s, %s)\n", scene->id.name, ma->id.name);
-
- /* Prevent infinite recursion by checking (and tagging the material) as having been visited already
- * (see BKE_scene_update_tagged()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else
- * in the meantime... [#32017]
- */
- if (ma->id.tag & LIB_TAG_DOIT)
- return;
-
- ma->id.tag |= LIB_TAG_DOIT;
-
- /* material itself */
- if (ma->adt && ma->adt->drivers.first) {
- BKE_animsys_evaluate_animdata(scene, &ma->id, ma->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* nodes */
- if (ma->nodetree) {
- material_node_drivers_update(scene, ma->nodetree, ctime);
- }
-
- ma->id.tag &= ~LIB_TAG_DOIT;
-}
-
bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
{
Material *mao, ***matarar;
@@ -1287,23 +998,16 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
}
/* check indices from mesh */
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) {
material_data_index_remove_id((ID *)ob->data, actcol - 1);
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
}
}
return true;
}
-static bool get_mtex_slot_valid_texpaint(struct MTex *mtex)
-{
- return (mtex && (mtex->texco == TEXCO_UV) &&
- mtex->tex && (mtex->tex->type == TEX_IMAGE) &&
- mtex->tex->ima);
-}
-
static bNode *nodetree_uv_node_recursive(bNode *node)
{
bNode *inode;
@@ -1324,14 +1028,58 @@ static bNode *nodetree_uv_node_recursive(bNode *node)
return NULL;
}
-void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
+static int count_texture_nodes_recursive(bNodeTree *nodetree)
{
- MTex **mtex;
- short count = 0;
- short index = 0, i;
+ int tex_nodes = 0;
+
+ for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+ tex_nodes++;
+ }
+ else if (node->type == NODE_GROUP) {
+ /* recurse into the node group and see if it contains any textures */
+ tex_nodes += count_texture_nodes_recursive((bNodeTree *)node->id);
+ }
+ }
+
+ return tex_nodes;
+}
+
+static void fill_texpaint_slots_recursive(bNodeTree *nodetree, bNode *active_node, Material *ma, int *index)
+{
+ for (bNode *node = nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+ if (active_node == node) {
+ ma->paint_active_slot = *index;
+ }
+ ma->texpaintslot[*index].ima = (Image *)node->id;
+
+ /* for new renderer, we need to traverse the treeback in search of a UV node */
+ bNode *uvnode = nodetree_uv_node_recursive(node);
+
+ if (uvnode) {
+ NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
+ ma->texpaintslot[*index].uvname = storage->uv_map;
+ /* set a value to index so UI knows that we have a valid pointer for the mesh */
+ ma->texpaintslot[*index].valid = true;
+ }
+ else {
+ /* just invalidate the index here so UV map does not get displayed on the UI */
+ ma->texpaintslot[*index].valid = false;
+ }
+ (*index)++;
+ }
+ else if (node->type == NODE_GROUP) {
+ /* recurse into the node group and see if it contains any textures */
+ fill_texpaint_slots_recursive((bNodeTree *)node->id, active_node, ma, index);
+ }
+ }
+}
- 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);
+void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
+{
+ int count = 0;
+ int index = 0;
if (!ma)
return;
@@ -1348,88 +1096,25 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
return;
}
- if (use_nodes || ma->use_nodes) {
- bNode *node, *active_node;
-
- if (!(ma->nodetree)) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
-
- for (node = ma->nodetree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id)
- count++;
- }
-
- if (count == 0) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
- ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
-
- active_node = nodeGetActiveTexture(ma->nodetree);
-
- for (node = ma->nodetree->nodes.first; node; node = node->next) {
- if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
- if (active_node == node)
- ma->paint_active_slot = index;
- ma->texpaintslot[index].ima = (Image *)node->id;
-
- /* for new renderer, we need to traverse the treeback in search of a UV node */
- if (use_nodes) {
- bNode *uvnode = nodetree_uv_node_recursive(node);
-
- if (uvnode) {
- NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
- ma->texpaintslot[index].uvname = storage->uv_map;
- /* set a value to index so UI knows that we have a valid pointer for the mesh */
- ma->texpaintslot[index].index = 0;
- }
- else {
- /* just invalidate the index here so UV map does not get displayed on the UI */
- ma->texpaintslot[index].index = -1;
- }
- }
- else {
- ma->texpaintslot[index].index = -1;
- }
- index++;
- }
- }
+ if (!(ma->nodetree)) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
}
- else if (is_bi) {
- for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
- if (get_mtex_slot_valid_texpaint(*mtex)) {
- count++;
- }
- }
-
- if (count == 0) {
- ma->paint_active_slot = 0;
- ma->paint_clone_slot = 0;
- return;
- }
- ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+ count = count_texture_nodes_recursive(ma->nodetree);
- for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
- if (get_mtex_slot_valid_texpaint(*mtex)) {
- ma->texpaintslot[index].ima = (*mtex)->tex->ima;
- ma->texpaintslot[index].uvname = (*mtex)->uvname;
- ma->texpaintslot[index].index = i;
-
- index++;
- }
- }
- }
- else {
+ if (count == 0) {
ma->paint_active_slot = 0;
ma->paint_clone_slot = 0;
return;
}
+ ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+
+ bNode *active_node = nodeGetActiveTexture(ma->nodetree);
+
+ fill_texpaint_slots_recursive(ma->nodetree, active_node, ma, &index);
ma->tot_slots = count;
@@ -1685,21 +1370,6 @@ void clear_matcopybuf(void)
void free_matcopybuf(void)
{
- int a;
-
- for (a = 0; a < MAX_MTEX; a++) {
- if (matcopybuf.mtex[a]) {
- MEM_freeN(matcopybuf.mtex[a]);
- matcopybuf.mtex[a] = NULL;
- }
- }
-
- if (matcopybuf.ramp_col) MEM_freeN(matcopybuf.ramp_col);
- if (matcopybuf.ramp_spec) MEM_freeN(matcopybuf.ramp_spec);
-
- matcopybuf.ramp_col = NULL;
- matcopybuf.ramp_spec = NULL;
-
if (matcopybuf.nodetree) {
ntreeFreeTree(matcopybuf.nodetree);
MEM_freeN(matcopybuf.nodetree);
@@ -1711,574 +1381,42 @@ void free_matcopybuf(void)
void copy_matcopybuf(Main *bmain, Material *ma)
{
- int a;
- MTex *mtex;
-
if (matcopied)
free_matcopybuf();
memcpy(&matcopybuf, ma, sizeof(Material));
- if (matcopybuf.ramp_col) matcopybuf.ramp_col = MEM_dupallocN(matcopybuf.ramp_col);
- if (matcopybuf.ramp_spec) matcopybuf.ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = matcopybuf.mtex[a];
- if (mtex) {
- matcopybuf.mtex[a] = MEM_dupallocN(mtex);
- }
- }
matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, bmain, false);
matcopybuf.preview = NULL;
BLI_listbase_clear(&matcopybuf.gpumaterial);
+ /* TODO Duplicate Engine Settings and set runtime to NULL */
matcopied = 1;
}
void paste_matcopybuf(Main *bmain, Material *ma)
{
- int a;
- MTex *mtex;
ID id;
if (matcopied == 0)
return;
- /* free current mat */
- if (ma->ramp_col) MEM_freeN(ma->ramp_col);
- if (ma->ramp_spec) MEM_freeN(ma->ramp_spec);
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
- if (mtex && mtex->tex)
- id_us_min(&mtex->tex->id);
- if (mtex)
- MEM_freeN(mtex);
- }
+
+ /* Free gpu material before the ntree */
+ GPU_material_free(&ma->gpumaterial);
if (ma->nodetree) {
ntreeFreeTree(ma->nodetree);
MEM_freeN(ma->nodetree);
}
- GPU_material_free(&ma->gpumaterial);
-
id = (ma->id);
memcpy(ma, &matcopybuf, sizeof(Material));
(ma->id) = id;
- if (matcopybuf.ramp_col) ma->ramp_col = MEM_dupallocN(matcopybuf.ramp_col);
- if (matcopybuf.ramp_spec) ma->ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec);
-
- for (a = 0; a < MAX_MTEX; a++) {
- mtex = ma->mtex[a];
- if (mtex) {
- ma->mtex[a] = MEM_dupallocN(mtex);
- if (mtex->tex) {
- /* first check this is in main (we may have loaded another file) [#35500] */
- if (BLI_findindex(&bmain->tex, mtex->tex) != -1) {
- id_us_plus((ID *)mtex->tex);
- }
- else {
- ma->mtex[a]->tex = NULL;
- }
- }
- }
- }
-
ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false);
}
-
-/*********************** texface to material convert functions **********************/
-/* encode all the TF information into a single int */
-static int encode_tfaceflag(MTFace *tf, int convertall)
-{
- /* calculate the flag */
- int flag = tf->mode;
-
- /* options that change the material offline render */
- if (!convertall) {
- flag &= ~TF_OBCOL;
- }
-
- /* clean flags that are not being converted */
- flag &= ~TF_TEX;
- flag &= ~TF_SHAREDVERT;
- flag &= ~TF_SHAREDCOL;
- flag &= ~TF_CONVERTED;
-
- /* light tface flag is ignored in GLSL mode */
- flag &= ~TF_LIGHT;
-
- /* 15 is how big the flag can be - hardcoded here and in decode_tfaceflag() */
- flag |= tf->transp << 15;
-
- /* increase 1 so flag 0 is different than no flag yet */
- return flag + 1;
-}
-
-/* set the material options based in the tface flag */
-static void decode_tfaceflag(Material *ma, int flag, int convertall)
-{
- int alphablend;
- GameSettings *game = &ma->game;
-
- /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
- flag -= 1;
-
- alphablend = flag >> 15; /* encoded in the encode_tfaceflag function */
- (*game).flag = 0;
-
- /* General Material Options */
- if ((flag & TF_DYNAMIC) == 0) (*game).flag |= GEMAT_NOPHYSICS;
-
- /* Material Offline Rendering Properties */
- if (convertall) {
- if (flag & TF_OBCOL) ma->shade_flag |= MA_OBCOLOR;
- }
-
- /* Special Face Properties */
- if ((flag & TF_TWOSIDE) == 0) (*game).flag |= GEMAT_BACKCULL;
- if (flag & TF_INVISIBLE) (*game).flag |= GEMAT_INVISIBLE;
- if (flag & TF_BMFONT) (*game).flag |= GEMAT_TEXT;
-
- /* Face Orientation */
- if (flag & TF_BILLBOARD) (*game).face_orientation |= GEMAT_HALO;
- else if (flag & TF_BILLBOARD2) (*game).face_orientation |= GEMAT_BILLBOARD;
- else if (flag & TF_SHADOW) (*game).face_orientation |= GEMAT_SHADOW;
-
- /* Alpha Blend */
- if (flag & TF_ALPHASORT && ELEM(alphablend, TF_ALPHA, TF_ADD)) (*game).alpha_blend = GEMAT_ALPHA_SORT;
- else if (alphablend & TF_ALPHA) (*game).alpha_blend = GEMAT_ALPHA;
- else if (alphablend & TF_ADD) (*game).alpha_blend = GEMAT_ADD;
- else if (alphablend & TF_CLIP) (*game).alpha_blend = GEMAT_CLIP;
-}
-
-/* boolean check to see if the mesh needs a material */
-static int check_tfaceneedmaterial(int flag)
+void BKE_material_eval(struct Depsgraph *depsgraph, Material *material)
{
- /* check if the flags we have are not deprecated != than default material options
- * also if only flags are visible and collision see if all objects using this mesh have this option in physics */
-
- /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
- flag -= 1;
-
- /* deprecated flags */
- flag &= ~TF_OBCOL;
- flag &= ~TF_SHAREDVERT;
- flag &= ~TF_SHAREDCOL;
-
- /* light tface flag is ignored in GLSL mode */
- flag &= ~TF_LIGHT;
-
- /* automatic detected if tex image has alpha */
- flag &= ~(TF_ALPHA << 15);
- /* automatic detected if using texture */
- flag &= ~TF_TEX;
-
- /* settings for the default NoMaterial */
- if (flag == TF_DYNAMIC)
- return 0;
-
- else
- return 1;
-}
-
-/* return number of digits of an integer */
-/* XXX to be optmized or replaced by an equivalent blender internal function */
-static int integer_getdigits(int number)
-{
- int i = 0;
- if (number == 0) return 1;
-
- while (number != 0) {
- number = (int)(number / 10);
- i++;
- }
- return i;
-}
-
-static void calculate_tface_materialname(char *matname, char *newname, int flag)
-{
- /* if flag has only light and collision and material matches those values
- * you can do strcpy(name, mat_name);
- * otherwise do: */
- int digits = integer_getdigits(flag);
- /* clamp the old name, remove the MA prefix and add the .TF.flag suffix
- * e.g. matname = "MALoooooooooooooongName"; newname = "Loooooooooooooon.TF.2" */
- BLI_snprintf(newname, MAX_ID_NAME, "%.*s.TF.%0*d", MAX_ID_NAME - (digits + 5), matname, digits, flag);
-}
-
-/* returns -1 if no match */
-static short mesh_getmaterialnumber(Mesh *me, Material *ma)
-{
- short a;
-
- for (a = 0; a < me->totcol; a++) {
- if (me->mat[a] == ma) {
- return a;
- }
- }
-
- return -1;
-}
-
-/* append material */
-static short mesh_addmaterial(Main *bmain, Mesh *me, Material *ma)
-{
- BKE_material_append_id(bmain, &me->id, NULL);
- me->mat[me->totcol - 1] = ma;
-
- id_us_plus(&ma->id);
-
- return me->totcol - 1;
-}
-
-static void set_facetexture_flags(Material *ma, Image *image)
-{
- if (image) {
- ma->mode |= MA_FACETEXTURE;
- /* we could check if the texture has alpha, but then more meshes sharing the same
- * material may need it. Let's make it simple. */
- if (BKE_image_has_alpha(image))
- ma->mode |= MA_FACETEXTURE_ALPHA;
- }
-}
-
-/* returns material number */
-static short convert_tfacenomaterial(Main *bmain, Mesh *me, MTFace *tf, int flag)
-{
- Material *ma;
- char idname[MAX_ID_NAME];
- short mat_nr = -1;
-
- /* new material, the name uses the flag*/
- BLI_snprintf(idname, sizeof(idname), "MAMaterial.TF.%0*d", integer_getdigits(flag), flag);
-
- if ((ma = BLI_findstring(&bmain->mat, idname + 2, offsetof(ID, name) + 2))) {
- mat_nr = mesh_getmaterialnumber(me, ma);
- /* assign the material to the mesh */
- if (mat_nr == -1) mat_nr = mesh_addmaterial(bmain, me, ma);
-
- /* if needed set "Face Textures [Alpha]" Material options */
- set_facetexture_flags(ma, tf->tpage);
- }
- /* create a new material */
- else {
- ma = BKE_material_add(bmain, idname + 2);
-
- if (ma) {
- printf("TexFace Convert: Material \"%s\" created.\n", idname + 2);
- mat_nr = mesh_addmaterial(bmain, me, ma);
-
- /* if needed set "Face Textures [Alpha]" Material options */
- set_facetexture_flags(ma, tf->tpage);
-
- decode_tfaceflag(ma, flag, 1);
- /* the final decoding will happen after, outside the main loop
- * for now store the flag into the material and change light/tex/collision
- * store the flag as a negative number */
- ma->game.flag = -flag;
- id_us_min((ID *)ma);
- }
- else {
- printf("Error: Unable to create Material \"%s\" for Mesh \"%s\".", idname + 2, me->id.name + 2);
- }
- }
-
- /* set as converted, no need to go bad to this face */
- tf->mode |= TF_CONVERTED;
- return mat_nr;
-}
-
-/* Function to fully convert materials */
-static void convert_tfacematerial(Main *bmain, Material *ma)
-{
- Mesh *me;
- Material *mat_new;
- MFace *mf;
- MTFace *tf;
- int flag, index;
- int a;
- short mat_nr;
- CustomDataLayer *cdl;
- char idname[MAX_ID_NAME];
-
- for (me = bmain->mesh.first; me; me = me->id.next) {
- /* check if this mesh uses this material */
- for (a = 0; a < me->totcol; a++)
- if (me->mat[a] == ma) break;
-
- /* no material found */
- if (a == me->totcol) continue;
-
- /* get the active tface layer */
- index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl = (index == -1) ? NULL : &me->fdata.layers[index];
- if (!cdl) continue;
-
- /* loop over all the faces and stop at the ones that use the material*/
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (me->mat[mf->mat_nr] != ma) continue;
-
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
- flag = encode_tfaceflag(tf, 1);
-
- /* the name of the new material */
- calculate_tface_materialname(ma->id.name, (char *)&idname, flag);
-
- if ((mat_new = BLI_findstring(&bmain->mat, idname + 2, offsetof(ID, name) + 2))) {
- /* material already existent, see if the mesh has it */
- mat_nr = mesh_getmaterialnumber(me, mat_new);
- /* material is not in the mesh, add it */
- if (mat_nr == -1) mat_nr = mesh_addmaterial(bmain, me, mat_new);
- }
- /* create a new material */
- else {
- mat_new = BKE_material_copy(bmain, ma);
- if (mat_new) {
- /* rename the material*/
- BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name));
- id_us_min((ID *)mat_new);
-
- mat_nr = mesh_addmaterial(bmain, me, mat_new);
- decode_tfaceflag(mat_new, flag, 1);
- }
- else {
- printf("Error: Unable to create Material \"%s\" for Mesh \"%s.", idname + 2, me->id.name + 2);
- mat_nr = mf->mat_nr;
- continue;
- }
- }
-
- /* if the material has a texture but no texture channel
- * set "Face Textures [Alpha]" Material options
- * actually we need to run it always, because of old behavior
- * of using face texture if any texture channel was present (multitex) */
- //if ((!mat_new->mtex[0]) && (!mat_new->mtex[0]->tex))
- set_facetexture_flags(mat_new, tf->tpage);
-
- /* set the material number to the face*/
- mf->mat_nr = mat_nr;
- }
- /* remove material from mesh */
- for (a = 0; a < me->totcol; ) {
- if (me->mat[a] == ma) {
- BKE_material_pop_id(bmain, &me->id, a, true);
- }
- else {
- a++;
- }
- }
- }
-}
-
-
-#define MAT_BGE_DISPUTED -99999
-
-int do_version_tface(Main *main)
-{
- Mesh *me;
- Material *ma;
- MFace *mf;
- MTFace *tf;
- CustomDataLayer *cdl;
- int a;
- int flag;
- int index;
-
- /* Operator in help menu has been removed for 2.7x */
- int fileload = 1;
-
- /* sometimes mesh has no materials but will need a new one. In those
- * cases we need to ignore the mf->mat_nr and only look at the face
- * mode because it can be zero as uninitialized or the 1st created material
- */
- int nomaterialslots;
-
- /* alert to user to check the console */
- int nowarning = 1;
-
- /* mark all the materials to conversion with a flag
- * if there is tface create a complete flag for that storing in flag
- * if there is tface and flag > 0: creates a new flag based on this face
- * if flags are different set flag to -1
- */
-
- /* 1st part: marking mesh materials to update */
- for (me = main->mesh.first; me; me = me->id.next) {
- if (ID_IS_LINKED(me)) continue;
-
- /* get the active tface layer */
- index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl = (index == -1) ? NULL : &me->fdata.layers[index];
- if (!cdl) continue;
-
- nomaterialslots = (me->totcol == 0 ? 1 : 0);
-
- /* loop over all the faces*/
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
-
- /* conversion should happen only once */
- if (fileload)
- tf->mode &= ~TF_CONVERTED;
- else {
- if ((tf->mode & TF_CONVERTED)) continue;
- else tf->mode |= TF_CONVERTED;
- }
-
- /* no material slots */
- if (nomaterialslots) {
- flag = encode_tfaceflag(tf, 1);
-
- /* create/find a new material and assign to the face */
- if (check_tfaceneedmaterial(flag)) {
- mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag);
- }
- /* else mark them as no-material to be reverted to 0 later */
- else {
- mf->mat_nr = -1;
- }
- }
- else if (mf->mat_nr < me->totcol) {
- ma = me->mat[mf->mat_nr];
-
- /* no material create one if necessary */
- if (!ma) {
- /* find a new material and assign to the face */
- flag = encode_tfaceflag(tf, 1);
-
- /* create/find a new material and assign to the face */
- if (check_tfaceneedmaterial(flag))
- mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag);
-
- continue;
- }
-
- /* we can't read from this if it comes from a library,
- * at doversion time: direct_link might not have happened on it,
- * so ma->mtex is not pointing to valid memory yet.
- * later we could, but it's better not */
- else if (ID_IS_LINKED(ma))
- continue;
-
- /* material already marked as disputed */
- else if (ma->game.flag == MAT_BGE_DISPUTED)
- continue;
-
- /* found a material */
- else {
- flag = encode_tfaceflag(tf, ((fileload) ? 0 : 1));
-
- /* first time changing this material */
- if (ma->game.flag == 0)
- ma->game.flag = -flag;
-
- /* mark material as disputed */
- else if (ma->game.flag != -flag) {
- ma->game.flag = MAT_BGE_DISPUTED;
- continue;
- }
-
- /* material ok so far */
- else {
- ma->game.flag = -flag;
-
- /* some people uses multitexture with TexFace by creating a texture
- * channel which not necessarily the tf->tpage image. But the game engine
- * was enabling it. Now it's required to set "Face Texture [Alpha] in the
- * material settings. */
- if (!fileload)
- set_facetexture_flags(ma, tf->tpage);
- }
- }
- }
- else {
- continue;
- }
- }
-
- /* if we didn't have material slot and now we do, we need to
- * make sure the materials are correct */
- if (nomaterialslots) {
- if (me->totcol > 0) {
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (mf->mat_nr == -1) {
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
- mf->mat_nr = convert_tfacenomaterial(main, me, tf, encode_tfaceflag(tf, 1));
- }
- }
- }
- else {
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- mf->mat_nr = 0;
- }
- }
- }
-
- }
-
- /* 2nd part - conversion */
- /* skip library files */
-
- /* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */
- for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) {
- if (ID_IS_LINKED(ma)) continue;
-
- /* disputed material */
- if (ma->game.flag == MAT_BGE_DISPUTED) {
- ma->game.flag = 0;
- if (fileload) {
- printf("Warning: material \"%s\" skipped.\n", ma->id.name + 2);
- nowarning = 0;
- }
- else {
- convert_tfacematerial(main, ma);
- }
- continue;
- }
-
- /* no conflicts in this material - 90% of cases
- * convert from tface system to material */
- else if (ma->game.flag < 0) {
- decode_tfaceflag(ma, -(ma->game.flag), 1);
-
- /* material is good make sure all faces using
- * this material are set to converted */
- if (fileload) {
- for (me = main->mesh.first; me; me = me->id.next) {
- /* check if this mesh uses this material */
- for (a = 0; a < me->totcol; a++)
- if (me->mat[a] == ma) break;
-
- /* no material found */
- if (a == me->totcol) continue;
-
- /* get the active tface layer */
- index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl = (index == -1) ? NULL : &me->fdata.layers[index];
- if (!cdl) continue;
-
- /* loop over all the faces and stop at the ones that use the material*/
- for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
- if (me->mat[mf->mat_nr] == ma) {
- /* texface data for this face */
- tf = ((MTFace *)cdl->data) + a;
- tf->mode |= TF_CONVERTED;
- }
- }
- }
- }
- }
- /* material is not used by faces with texface
- * set the default flag - do it only once */
- else {
- if (fileload) {
- ma->game.flag = GEMAT_BACKCULL;
- }
- }
- }
-
- return nowarning;
+ DEG_debug_print_eval(depsgraph, __func__, material->id.name, material);
+ GPU_material_free(&material->gpumaterial);
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 9e926e5ef53..63adcfc3cae 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -57,7 +57,6 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
-#include "BKE_depsgraph.h"
#include "BKE_scene.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -74,6 +73,8 @@ void BKE_mball_free(MetaBall *mb)
{
BKE_animdata_free((ID *)mb, false);
+ BKE_mball_batch_cache_free(mb);
+
MEM_SAFE_FREE(mb->mat);
BLI_freelistN(&mb->elems);
@@ -119,6 +120,7 @@ void BKE_mball_copy_data(Main *UNUSED(bmain), MetaBall *mb_dst, const MetaBall *
mb_dst->editelems = NULL;
mb_dst->lastelem = NULL;
+ mb_dst->batch_cache = NULL;
}
MetaBall *BKE_mball_copy(Main *bmain, const MetaBall *mb)
@@ -203,7 +205,7 @@ void BKE_mball_texspace_calc(Object *ob)
(min)[0] = (min)[1] = (min)[2] = 1.0e30f;
(max)[0] = (max)[1] = (max)[2] = -1.0e30f;
- dl = ob->curve_cache->disp.first;
+ dl = ob->runtime.curve_cache->disp.first;
while (dl) {
tot = dl->nr;
if (tot) do_it = true;
@@ -220,20 +222,29 @@ void BKE_mball_texspace_calc(Object *ob)
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
-#if 0
- loc[0] = (min[0] + max[0]) / 2.0f;
- loc[1] = (min[1] + max[1]) / 2.0f;
- loc[2] = (min[2] + max[2]) / 2.0f;
-
- size[0] = (max[0] - min[0]) / 2.0f;
- size[1] = (max[1] - min[1]) / 2.0f;
- size[2] = (max[2] - min[2]) / 2.0f;
-#endif
+
BKE_boundbox_init_from_minmax(bb, min, max);
bb->flag &= ~BOUNDBOX_DIRTY;
}
+/** Return or compute bbox for given metaball object. */
+BoundBox *BKE_mball_boundbox_get(Object *ob)
+{
+ BLI_assert(ob->type == OB_MBALL);
+
+ if (ob->bb != NULL && (ob->bb->flag & BOUNDBOX_DIRTY) == 0) {
+ return ob->bb;
+ }
+
+ /* This should always only be called with evaluated objects, but currently RNA is a problem here... */
+ if (ob->runtime.curve_cache != NULL) {
+ BKE_mball_texspace_calc(ob);
+ }
+
+ return ob->bb;
+}
+
float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
{
BoundBox *bb;
@@ -299,6 +310,11 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
int basis1nr, basis2nr;
char basis1name[MAX_ID_NAME], basis2name[MAX_ID_NAME];
+ if (ob1->id.name[2] != ob2->id.name[2]) {
+ /* Quick return in case first char of both ID's names is not the same... */
+ return false;
+ }
+
BLI_split_name_num(basis1name, &basis1nr, ob1->id.name + 2, '.');
BLI_split_name_num(basis2name, &basis2nr, ob2->id.name + 2, '.');
@@ -310,13 +326,46 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
}
}
+bool BKE_mball_is_any_selected(const MetaBall *mb)
+{
+ for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool BKE_mball_is_any_selected_multi(Object **objects, int objects_len)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+ if (BKE_mball_is_any_selected(mb)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_mball_is_any_unselected(const MetaBall *mb)
+{
+ for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) {
+ if ((ml->flag & SELECT) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
/* \brief copy some properties from object to other metaball object with same base name
*
* When some properties (wiresize, threshold, update flags) of metaball are changed, then this properties
* are copied to all metaballs in same "group" (metaballs with same base name: MBall,
* MBall.001, MBall.002, etc). The most important is to copy properties to the base metaball,
* because this metaball influence polygonisation of metaballs. */
-void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *active_object)
+void BKE_mball_properties_copy(Scene *scene, Object *active_object)
{
Scene *sce_iter = scene;
Base *base;
@@ -328,8 +377,11 @@ void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *
BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.');
- BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &ob)) {
+ /* Pass depsgraph as NULL, which means we will not expand into
+ * duplis unlike when we generate the mball. Expanding duplis
+ * would not be compatible when editing multiple view layers. */
+ BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 1, &base, &ob)) {
if (ob->type == OB_MBALL) {
if (ob != active_object) {
BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
@@ -359,28 +411,27 @@ void BKE_mball_properties_copy(Main *bmain, EvaluationContext *eval_ctx, Scene *
*
* warning!, is_basis_mball() can fail on returned object, see long note above.
*/
-Object *BKE_mball_basis_find(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *basis)
+Object *BKE_mball_basis_find(Scene *scene, Object *basis)
{
- Scene *sce_iter = scene;
- Base *base;
- Object *ob, *bob = basis;
+ Object *bob = basis;
int basisnr, obnr;
char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
- SceneBaseIter iter;
BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &ob)) {
- if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) {
- if (ob != bob) {
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* object ob has to be in same "group" ... it means, that it has to have same base of its name */
- if (STREQ(obname, basisname)) {
- if (obnr < basisnr) {
- basis = ob;
- basisnr = obnr;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ Object *ob = base->object;
+ if ((ob->type == OB_MBALL) && !(base->flag & BASE_FROMDUPLI)) {
+ if (ob != bob) {
+ BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
+
+ /* object ob has to be in same "group" ... it means, that it has to have same base of its name */
+ if (STREQ(obname, basisname)) {
+ if (obnr < basisnr) {
+ basis = ob;
+ basisnr = obnr;
+ }
}
}
}
@@ -390,17 +441,17 @@ Object *BKE_mball_basis_find(Main *bmain, EvaluationContext *eval_ctx, Scene *sc
return basis;
}
-bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3],
- float obmat[4][4], const short flag)
+bool BKE_mball_minmax_ex(
+ const MetaBall *mb, float min[3], float max[3],
+ const float obmat[4][4], const short flag)
{
const float scale = obmat ? mat4_to_scale(obmat) : 1.0f;
- MetaElem *ml;
bool changed = false;
float centroid[3], vec[3];
INIT_MINMAX(min, max);
- for (ml = mb->elems.first; ml; ml = ml->next) {
+ for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
if ((ml->flag & flag) == flag) {
const float scale_mb = (ml->rad * 0.5f) * scale;
int i;
@@ -427,27 +478,24 @@ bool BKE_mball_minmax_ex(MetaBall *mb, float min[3], float max[3],
/* basic vertex data functions */
-bool BKE_mball_minmax(MetaBall *mb, float min[3], float max[3])
+bool BKE_mball_minmax(const MetaBall *mb, float min[3], float max[3])
{
- MetaElem *ml;
-
INIT_MINMAX(min, max);
- for (ml = mb->elems.first; ml; ml = ml->next) {
+ for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
minmax_v3v3_v3(min, max, &ml->x);
}
return (BLI_listbase_is_empty(&mb->elems) == false);
}
-bool BKE_mball_center_median(MetaBall *mb, float r_cent[3])
+bool BKE_mball_center_median(const MetaBall *mb, float r_cent[3])
{
- MetaElem *ml;
int total = 0;
zero_v3(r_cent);
- for (ml = mb->elems.first; ml; ml = ml->next) {
+ for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
add_v3_v3(r_cent, &ml->x);
total++;
}
@@ -459,7 +507,7 @@ bool BKE_mball_center_median(MetaBall *mb, float r_cent[3])
return (total != 0);
}
-bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3])
+bool BKE_mball_center_bounds(const MetaBall *mb, float r_cent[3])
{
float min[3], max[3];
@@ -473,26 +521,25 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3])
void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props)
{
- MetaElem *me;
float quat[4];
const float scale = mat4_to_scale(mat);
const float scale_sqrt = sqrtf(scale);
mat4_to_quat(quat, mat);
- for (me = mb->elems.first; me; me = me->next) {
- mul_m4_v3(mat, &me->x);
- mul_qt_qtqt(me->quat, quat, me->quat);
+ for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
+ mul_m4_v3(mat, &ml->x);
+ mul_qt_qtqt(ml->quat, quat, ml->quat);
if (do_props) {
- me->rad *= scale;
+ ml->rad *= scale;
/* hrmf, probably elems shouldn't be
* treating scale differently - campbell */
- if (!MB_TYPE_SIZE_SQUARED(me->type)) {
- mul_v3_fl(&me->expx, scale);
+ if (!MB_TYPE_SIZE_SQUARED(ml->type)) {
+ mul_v3_fl(&ml->expx, scale);
}
else {
- mul_v3_fl(&me->expx, scale_sqrt);
+ mul_v3_fl(&ml->expx, scale_sqrt);
}
}
}
@@ -500,44 +547,99 @@ void BKE_mball_transform(MetaBall *mb, float mat[4][4], const bool do_props)
void BKE_mball_translate(MetaBall *mb, const float offset[3])
{
- MetaElem *ml;
-
- for (ml = mb->elems.first; ml; ml = ml->next) {
+ for (MetaElem *ml = mb->elems.first; ml; ml = ml->next) {
add_v3_v3(&ml->x, offset);
}
}
/* *** select funcs *** */
-void BKE_mball_select_all(struct MetaBall *mb)
+int BKE_mball_select_count(const MetaBall *mb)
{
- MetaElem *ml;
+ int sel = 0;
+ for (const MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ sel++;
+ }
+ }
+ return sel;
+}
- for (ml = mb->editelems->first; ml; ml = ml->next) {
+int BKE_mball_select_count_multi(Object **objects, int objects_len)
+{
+ int sel = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ const Object *obedit = objects[ob_index];
+ const MetaBall *mb = (MetaBall *)obedit->data;
+ sel += BKE_mball_select_count(mb);
+ }
+ return sel;
+}
+
+void BKE_mball_select_all(MetaBall *mb)
+{
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
ml->flag |= SELECT;
}
}
-void BKE_mball_deselect_all(MetaBall *mb)
+void BKE_mball_select_all_multi(Object **objects, int objects_len)
{
- MetaElem *ml;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = obedit->data;
+ BKE_mball_select_all(mb);
+ }
+}
- for (ml = mb->editelems->first; ml; ml = ml->next) {
+void BKE_mball_deselect_all(MetaBall *mb)
+{
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
ml->flag &= ~SELECT;
}
}
-void BKE_mball_select_swap(struct MetaBall *mb)
+void BKE_mball_deselect_all_multi(Object **objects, int objects_len)
{
- MetaElem *ml;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = obedit->data;
+
+ BKE_mball_deselect_all(mb);
+ }
+}
- for (ml = mb->editelems->first; ml; ml = ml->next) {
+void BKE_mball_select_swap(MetaBall *mb)
+{
+ for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
ml->flag ^= SELECT;
}
}
+void BKE_mball_select_swap_multi(Object **objects, int objects_len)
+{
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ MetaBall *mb = (MetaBall *)obedit->data;
+ BKE_mball_select_swap(mb);
+ }
+}
+
/* **** Depsgraph evaluation **** */
-void BKE_mball_eval_geometry(EvaluationContext *UNUSED(eval_ctx),
- MetaBall *UNUSED(mball))
+/* Draw Engine */
+
+void (*BKE_mball_batch_cache_dirty_tag_cb)(MetaBall *mb, int mode) = NULL;
+void (*BKE_mball_batch_cache_free_cb)(MetaBall *mb) = NULL;
+
+void BKE_mball_batch_cache_dirty_tag(MetaBall *mb, int mode)
{
+ if (mb->batch_cache) {
+ BKE_mball_batch_cache_dirty_tag_cb(mb, mode);
+ }
+}
+void BKE_mball_batch_cache_free(MetaBall *mb)
+{
+ if (mb->batch_cache) {
+ BKE_mball_batch_cache_free_cb(mb);
+ }
}
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index cc82d12a776..436f5cc8afd 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -48,12 +48,14 @@
#include "BKE_global.h"
-#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_main.h"
#include "BKE_mball_tessellate.h" /* own include */
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "BLI_strict_flags.h"
/* experimental (faster) normal calculation */
@@ -837,27 +839,6 @@ static void vnormal(PROCESS *process, const float point[3], float r_no[3])
r_no[0] = metaball(process, point[0] + delta, point[1], point[2]) - f;
r_no[1] = metaball(process, point[0], point[1] + delta, point[2]) - f;
r_no[2] = metaball(process, point[0], point[1], point[2] + delta) - f;
-
-#if 0
- f = normalize_v3(r_no);
-
- if (0) {
- float tvec[3];
-
- delta *= 2.0f;
-
- f = process->function(process, point[0], point[1], point[2]);
-
- tvec[0] = process->function(process, point[0] + delta, point[1], point[2]) - f;
- tvec[1] = process->function(process, point[0], point[1] + delta, point[2]) - f;
- tvec[2] = process->function(process, point[0], point[1], point[2] + delta) - f;
-
- if (normalize_v3(tvec) != 0.0f) {
- add_v3_v3(r_no, tvec);
- normalize_v3(r_no);
- }
- }
-#endif
}
#endif /* USE_ACCUM_NORMAL */
@@ -1056,7 +1037,7 @@ static void polygonize(PROCESS *process)
* Iterates over ALL objects in the scene and all of its sets, including
* making all duplis(not only metas). Copies metas to mainb array.
* Computes bounding boxes for building BVH. */
-static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob)
+static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Object *ob)
{
Scene *sce_iter = scene;
Base *base;
@@ -1075,13 +1056,13 @@ static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process
BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
/* make main array */
- BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(bmain, eval_ctx, &iter, &sce_iter, 1, &base, &bob)) {
+ BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 0, NULL, NULL);
+ while (BKE_scene_base_iter_next(depsgraph, &iter, &sce_iter, 1, &base, &bob)) {
if (bob->type == OB_MBALL) {
zero_size = 0;
ml = NULL;
- if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) {
+ if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) {
mb = ob->data;
if (mb->editelems) ml = mb->editelems->first;
@@ -1233,12 +1214,13 @@ static void init_meta(Main *bmain, EvaluationContext *eval_ctx, PROCESS *process
}
}
-void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, ListBase *dispbase)
+void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase)
{
MetaBall *mb;
DispList *dl;
unsigned int a;
PROCESS process = {0};
+ bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
mb = ob->data;
@@ -1249,10 +1231,10 @@ void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene
else if (process.thresh < 0.1f) process.converge_res = 4;
else process.converge_res = 2;
- if ((eval_ctx->mode != DAG_EVAL_RENDER) && (mb->flag == MB_UPDATE_NEVER)) return;
+ if (is_render && (mb->flag == MB_UPDATE_NEVER)) return;
if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) return;
- if (eval_ctx->mode == DAG_EVAL_RENDER) {
+ if (is_render) {
process.size = mb->rendersize;
}
else {
@@ -1267,7 +1249,7 @@ void BKE_mball_polygonize(Main *bmain, EvaluationContext *eval_ctx, Scene *scene
process.pgn_elements = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "Metaball memarena");
/* initialize all mainb (MetaElems) */
- init_meta(bmain, eval_ctx, &process, scene, ob);
+ init_meta(depsgraph, &process, scene, ob);
if (process.totelem > 0) {
build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb);
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 5758e00a28d..6a00aaf576b 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -32,8 +32,10 @@
#include "DNA_object_types.h"
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
#include "BLI_math.h"
#include "BLI_linklist.h"
#include "BLI_memarena.h"
@@ -41,15 +43,15 @@
#include "BLI_string.h"
#include "BKE_animsys.h"
+#include "BKE_idcode.h"
#include "BKE_main.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
-#include "BKE_depsgraph.h"
#include "BKE_object.h"
#include "BKE_editmesh.h"
@@ -109,7 +111,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
for (i = 0; i < c1->totlayer; i++) {
if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i1++;
}
@@ -117,7 +119,7 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
for (i = 0; i < c2->totlayer; i++) {
if (ELEM(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i2++;
}
@@ -131,14 +133,14 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
i1 = 0; i2 = 0;
for (i = 0; i < tot; i++) {
while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i1++;
l1++;
}
while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MDEFORMVERT))
{
i2++;
l2++;
@@ -306,7 +308,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
* Callers could also check but safer to do here - campbell */
}
else {
- const int tottex_original = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+ const int tottex_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
@@ -317,16 +319,16 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
{
BKE_mesh_tessface_clear(me);
- CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface);
+ CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface);
/* TODO - add some --debug-mesh option */
if (G.debug & G_DEBUG) {
/* note: this warning may be un-called for if we are initializing the mesh for the
* first time from bmesh, rather then giving a warning about this we could be smarter
* and check if there was any data to begin with, for now just print the warning with
- * some info to help troubleshoot whats going on - campbell */
+ * some info to help troubleshoot what's going on - campbell */
printf("%s: warning! Tessellation uvs or vcol data got out of sync, "
- "had to reset!\n CD_MTFACE: %d != CD_MTEXPOLY: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n",
+ "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n",
__func__, tottex_tessface, tottex_original, totcol_tessface, totcol_original);
}
}
@@ -372,6 +374,49 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
}
}
+bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me)
+{
+ BMesh *bm = me->edit_btmesh ? me->edit_btmesh->bm : NULL;
+ bool changed = false;
+ if (bm) {
+ if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
+ BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP);
+ changed = true;
+ }
+ }
+ else {
+ if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ CustomData_add_layer(
+ &me->pdata,
+ CD_FACEMAP,
+ CD_DEFAULT,
+ NULL,
+ me->totpoly);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
+bool BKE_mesh_clear_facemap_customdata(struct Mesh *me)
+{
+ BMesh *bm = me->edit_btmesh ? me->edit_btmesh->bm : NULL;
+ bool changed = false;
+ if (bm) {
+ if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) {
+ BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP);
+ changed = true;
+ }
+ }
+ else {
+ if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ CustomData_free_layers(&me->pdata, CD_FACEMAP, me->totpoly);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
/* this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
* mloopcol and mcol) have the same relative active/render/clone/mask indices.
*
@@ -380,14 +425,11 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me)
* versions of the mesh. - campbell*/
static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd)
{
- if (me->edit_btmesh)
- BKE_editmesh_update_linked_customdata(me->edit_btmesh);
-
if (do_ensure_tess_cd) {
mesh_ensure_tessellation_customdata(me);
}
- CustomData_bmesh_update_active_layers(&me->fdata, &me->pdata, &me->ldata);
+ CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata);
}
void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
@@ -406,7 +448,6 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
- me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY);
me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
}
@@ -426,6 +467,8 @@ void BKE_mesh_free(Mesh *me)
{
BKE_animdata_free(&me->id, false);
+ BKE_mesh_runtime_clear_cache(me);
+
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
@@ -460,12 +503,7 @@ void BKE_mesh_init(Mesh *me)
me->size[0] = me->size[1] = me->size[2] = 1.0;
me->smoothresh = DEG2RADF(30);
me->texflag = ME_AUTOSPACE;
-
- /* disable because its slow on many GPU's, see [#37518] */
-#if 0
- me->flag = ME_TWOSIDED;
-#endif
- me->drawflag = ME_DRAWEDGES | ME_DRAWFACES | ME_DRAWCREASES;
+ me->drawflag = 0;
CustomData_reset(&me->vdata);
CustomData_reset(&me->edata);
@@ -496,15 +534,22 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name)
void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int flag)
{
const bool do_tessface = ((me_src->totface != 0) && (me_src->totpoly == 0)); /* only do tessface if we have no polys */
+ CustomDataMask mask = CD_MASK_MESH;
+
+ if (me_src->id.tag & LIB_TAG_NO_MAIN) {
+ /* For copies in depsgraph, keep data like origindex and orco. */
+ mask |= CD_MASK_DERIVEDMESH;
+ }
me_dst->mat = MEM_dupallocN(me_src->mat);
- CustomData_copy(&me_src->vdata, &me_dst->vdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totvert);
- CustomData_copy(&me_src->edata, &me_dst->edata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totedge);
- CustomData_copy(&me_src->ldata, &me_dst->ldata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totloop);
- CustomData_copy(&me_src->pdata, &me_dst->pdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totpoly);
+ const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, mask, alloc_type, me_dst->totvert);
+ CustomData_copy(&me_src->edata, &me_dst->edata, mask, alloc_type, me_dst->totedge);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, mask, alloc_type, me_dst->totloop);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, mask, alloc_type, me_dst->totpoly);
if (do_tessface) {
- CustomData_copy(&me_src->fdata, &me_dst->fdata, CD_MASK_MESH, CD_DUPLICATE, me_dst->totface);
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, mask, alloc_type, me_dst->totface);
}
else {
mesh_tessface_clear_intern(me_dst, false);
@@ -514,37 +559,223 @@ void BKE_mesh_copy_data(Main *bmain, Mesh *me_dst, const Mesh *me_src, const int
me_dst->edit_btmesh = NULL;
+ /* Call BKE_mesh_runtime_reset? */
+ me_dst->runtime.batch_cache = NULL;
+ me_dst->runtime.looptris.array = NULL;
+ me_dst->runtime.bvh_cache = NULL;
+ me_dst->runtime.shrinkwrap_data = NULL;
+
+ if (me_src->id.tag & LIB_TAG_NO_MAIN) {
+ me_dst->runtime.deformed_only = me_src->runtime.deformed_only;
+ }
+ else {
+ /* This is a direct copy of a main mesh, so for now it has the same topology. */
+ me_dst->runtime.deformed_only = 1;
+ }
+ me_dst->runtime.is_original = false;
+
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
me_dst->bb = MEM_dupallocN(me_dst->bb);
/* TODO Do we want to add flag to prevent this? */
- if (me_src->key) {
+ if (me_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &me_src->key->id, (ID **)&me_dst->key, flag, false);
}
}
+/* Custom data layer functions; those assume that totXXX are set correctly. */
+static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface)
+{
+ if (!CustomData_get_layer(&mesh->vdata, CD_MVERT))
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+ if (!CustomData_get_layer(&mesh->edata, CD_MEDGE))
+ CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+ if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP))
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
+ if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY))
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
+
+ if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE))
+ CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface);
+}
+static void mesh_ensure_cdlayers_origindex(Mesh *mesh, bool do_tessface)
+{
+ if (!CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
+ if (!CustomData_get_layer(&mesh->edata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
+ if (!CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly);
+
+ if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX))
+ CustomData_add_layer(&mesh->fdata, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
+}
+
+Mesh *BKE_mesh_new_nomain(int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
+{
+ Mesh *mesh = BKE_libblock_alloc(
+ NULL, ID_ME,
+ BKE_idcode_to_name(ID_ME),
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG);
+ BKE_libblock_init_empty(&mesh->id);
+
+ /* don't use CustomData_reset(...); because we dont want to touch customdata */
+ copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1);
+ copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1);
+
+ mesh->totvert = verts_len;
+ mesh->totedge = edges_len;
+ mesh->totface = tessface_len;
+ mesh->totloop = loops_len;
+ mesh->totpoly = polys_len;
+
+ mesh_ensure_cdlayers_primary(mesh, true);
+ mesh_ensure_cdlayers_origindex(mesh, true);
+ BKE_mesh_update_customdata_pointers(mesh, false);
+
+ return mesh;
+}
+
+static Mesh *mesh_new_nomain_from_template_ex(
+ const Mesh *me_src,
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len,
+ CustomDataMask mask)
+{
+ /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
+ const bool do_tessface = (tessface_len ||
+ ((me_src->totface != 0) && (me_src->totpoly == 0)));
+
+ Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
+
+ me_dst->mat = MEM_dupallocN(me_src->mat);
+ me_dst->mselect = MEM_dupallocN(me_dst->mselect);
+
+ me_dst->totvert = verts_len;
+ me_dst->totedge = edges_len;
+ me_dst->totface = tessface_len;
+ me_dst->totloop = loops_len;
+ me_dst->totpoly = polys_len;
+
+ CustomData_copy(&me_src->vdata, &me_dst->vdata, mask, CD_CALLOC, verts_len);
+ CustomData_copy(&me_src->edata, &me_dst->edata, mask, CD_CALLOC, edges_len);
+ CustomData_copy(&me_src->ldata, &me_dst->ldata, mask, CD_CALLOC, loops_len);
+ CustomData_copy(&me_src->pdata, &me_dst->pdata, mask, CD_CALLOC, polys_len);
+ if (do_tessface) {
+ CustomData_copy(&me_src->fdata, &me_dst->fdata, mask, CD_CALLOC, tessface_len);
+ }
+ else {
+ mesh_tessface_clear_intern(me_dst, false);
+ }
+
+ /* The destination mesh should at least have valid primary CD layers,
+ * even in cases where the source mesh does not. */
+ mesh_ensure_cdlayers_primary(me_dst, do_tessface);
+ mesh_ensure_cdlayers_origindex(me_dst, false);
+ BKE_mesh_update_customdata_pointers(me_dst, false);
+
+ return me_dst;
+}
+
+Mesh *BKE_mesh_new_nomain_from_template(
+ const Mesh *me_src,
+ int verts_len, int edges_len, int tessface_len,
+ int loops_len, int polys_len)
+{
+ return mesh_new_nomain_from_template_ex(
+ me_src,
+ verts_len, edges_len, tessface_len,
+ loops_len, polys_len,
+ CD_MASK_EVERYTHING);
+}
+
+Mesh *BKE_mesh_copy_for_eval(struct Mesh *source, bool reference)
+{
+ int flags = (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW);
+
+ if (reference) {
+ flags |= LIB_ID_COPY_CD_REFERENCE;
+ }
+
+ Mesh *result;
+ BKE_id_copy_ex(NULL, &source->id, (ID **)&result, flags, false);
+ return result;
+}
+
Mesh *BKE_mesh_copy(Main *bmain, const Mesh *me)
{
Mesh *me_copy;
- BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, 0, false);
+ BKE_id_copy_ex(bmain, &me->id, (ID **)&me_copy, LIB_ID_COPY_SHAPEKEY, false);
return me_copy;
}
+BMesh *BKE_mesh_to_bmesh_ex(
+ Mesh *me,
+ const struct BMeshCreateParams *create_params,
+ const struct BMeshFromMeshParams *convert_params)
+{
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+
+ bm = BM_mesh_create(&allocsize, create_params);
+ BM_mesh_bm_from_me(bm, me, convert_params);
+
+ return bm;
+}
+
BMesh *BKE_mesh_to_bmesh(
Mesh *me, Object *ob,
const bool add_key_index, const struct BMeshCreateParams *params)
{
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+ return BKE_mesh_to_bmesh_ex(
+ me, params,
+ &(struct BMeshFromMeshParams){
+ .calc_face_normal = false,
+ .add_key_index = add_key_index,
+ .use_shapekey = true,
+ .active_shapekey = ob->shapenr,
+ });
+}
- bm = BM_mesh_create(&allocsize, params);
+Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params)
+{
+ BLI_assert(params->calc_object_remap == false);
+ Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
+ BM_mesh_bm_to_me(NULL, bm, mesh, params);
+ return mesh;
+}
- BM_mesh_bm_from_me(
- bm, me, (&(struct BMeshFromMeshParams){
- .add_key_index = add_key_index, .use_shapekey = true, .active_shapekey = ob->shapenr,
- }));
+Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const int64_t cd_mask_extra)
+{
+ Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
+ BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
+ return mesh;
+}
- return bm;
+/**
+ * TODO(campbell): support mesh with only an edit-mesh which is lazy initialized.
+ */
+Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
+ BMEditMesh *em, CustomDataMask data_mask, float (*vertexCos)[3])
+{
+ Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask);
+ /* Use editmesh directly where possible. */
+ me->runtime.is_original = true;
+ if (vertexCos) {
+ /* We will own this array in the future. */
+ BKE_mesh_apply_vert_coords(me, vertexCos);
+ MEM_freeN(vertexCos);
+ me->runtime.is_original = false;
+ }
+ return me;
}
void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
@@ -553,121 +784,82 @@ void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
}
bool BKE_mesh_uv_cdlayer_rename_index(
- Mesh *me, const int poly_index, const int loop_index, const int face_index,
+ Mesh *me, const int loop_index, const int face_index,
const char *new_name, const bool do_tessface)
{
- CustomData *pdata, *ldata, *fdata;
- CustomDataLayer *cdlp, *cdlu, *cdlf;
- const int step = do_tessface ? 3 : 2;
- int i;
+ CustomData *ldata, *fdata;
+ CustomDataLayer *cdlu, *cdlf;
if (me->edit_btmesh) {
- pdata = &me->edit_btmesh->bm->pdata;
ldata = &me->edit_btmesh->bm->ldata;
fdata = NULL; /* No tessellated data in BMesh! */
}
else {
- pdata = &me->pdata;
ldata = &me->ldata;
fdata = &me->fdata;
}
- cdlp = &pdata->layers[poly_index];
+
cdlu = &ldata->layers[loop_index];
- cdlf = fdata && do_tessface ? &fdata->layers[face_index] : NULL;
+ cdlf = (face_index != -1) && fdata && do_tessface ? &fdata->layers[face_index] : NULL;
- if (cdlp->name != new_name) {
+ if (cdlu->name != new_name) {
/* Mesh validate passes a name from the CD layer as the new name,
* Avoid memcpy from self to self in this case.
*/
- BLI_strncpy(cdlp->name, new_name, sizeof(cdlp->name));
- CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers);
+ BLI_strncpy(cdlu->name, new_name, sizeof(cdlu->name));
+ CustomData_set_layer_unique_name(ldata, loop_index);
}
- /* Loop until we do have exactly the same name for all layers! */
- for (i = 1; !STREQ(cdlp->name, cdlu->name) || (cdlf && !STREQ(cdlp->name, cdlf->name)); i++) {
- switch (i % step) {
- case 0:
- BLI_strncpy(cdlp->name, cdlu->name, sizeof(cdlp->name));
- CustomData_set_layer_unique_name(pdata, cdlp - pdata->layers);
- break;
- case 1:
- BLI_strncpy(cdlu->name, cdlp->name, sizeof(cdlu->name));
- CustomData_set_layer_unique_name(ldata, cdlu - ldata->layers);
- break;
- case 2:
- if (cdlf) {
- BLI_strncpy(cdlf->name, cdlp->name, sizeof(cdlf->name));
- CustomData_set_layer_unique_name(fdata, cdlf - fdata->layers);
- }
- break;
- }
+ if (cdlf == NULL) {
+ return false;
}
+ BLI_strncpy(cdlf->name, cdlu->name, sizeof(cdlf->name));
+ CustomData_set_layer_unique_name(fdata, face_index);
+
return true;
}
bool BKE_mesh_uv_cdlayer_rename(Mesh *me, const char *old_name, const char *new_name, bool do_tessface)
{
- CustomData *pdata, *ldata, *fdata;
+ CustomData *ldata, *fdata;
if (me->edit_btmesh) {
- pdata = &me->edit_btmesh->bm->pdata;
ldata = &me->edit_btmesh->bm->ldata;
/* No tessellated data in BMesh! */
fdata = NULL;
do_tessface = false;
}
else {
- pdata = &me->pdata;
ldata = &me->ldata;
fdata = &me->fdata;
do_tessface = (do_tessface && fdata->totlayer);
}
{
- const int pidx_start = CustomData_get_layer_index(pdata, CD_MTEXPOLY);
const int lidx_start = CustomData_get_layer_index(ldata, CD_MLOOPUV);
const int fidx_start = do_tessface ? CustomData_get_layer_index(fdata, CD_MTFACE) : -1;
- int pidx = CustomData_get_named_layer(pdata, CD_MTEXPOLY, old_name);
int lidx = CustomData_get_named_layer(ldata, CD_MLOOPUV, old_name);
int fidx = do_tessface ? CustomData_get_named_layer(fdata, CD_MTFACE, old_name) : -1;
/* None of those cases should happen, in theory!
* Note this assume we have the same number of mtexpoly, mloopuv and mtface layers!
*/
- if (pidx == -1) {
- if (lidx == -1) {
- if (fidx == -1) {
- /* No layer found with this name! */
- return false;
- }
- else {
- lidx = fidx;
- }
- }
- pidx = lidx;
- }
- else {
- if (lidx == -1) {
- lidx = pidx;
+ if (lidx == -1) {
+ if (fidx == -1) {
+ /* No layer found with this name! */
+ return false;
}
- if (fidx == -1 && do_tessface) {
- fidx = pidx;
+ else {
+ lidx = fidx;
}
}
-#if 0
- /* For now, we do not consider mismatch in indices (i.e. same name leading to (relative) different indices). */
- else if (pidx != lidx) {
- lidx = pidx;
- }
-#endif
/* Go back to absolute indices! */
- pidx += pidx_start;
lidx += lidx_start;
if (fidx != -1)
fidx += fidx_start;
- return BKE_mesh_uv_cdlayer_rename_index(me, pidx, lidx, fidx, new_name, do_tessface);
+ return BKE_mesh_uv_cdlayer_rename_index(me, lidx, fidx, new_name, do_tessface);
}
}
@@ -745,6 +937,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;
@@ -904,7 +1108,6 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me)
test_object_modifiers(ob);
}
-
void BKE_mesh_material_index_remove(Mesh *me, short index)
{
MPoly *mp;
@@ -999,15 +1202,15 @@ void BKE_mesh_smooth_flag_set(Object *meshOb, int enableSmooth)
/**
* Return a newly MEM_malloc'd array of all the mesh vertex locations
- * \note \a r_numVerts may be NULL
+ * \note \a r_verts_len may be NULL
*/
-float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_numVerts))[3]
+float (*BKE_mesh_vertexCos_get(const Mesh *me, int *r_verts_len))[3]
{
- int i, numVerts = me->totvert;
- float (*cos)[3] = MEM_malloc_arrayN(numVerts, sizeof(*cos), "vertexcos1");
+ int i, verts_len = me->totvert;
+ float (*cos)[3] = MEM_malloc_arrayN(verts_len, sizeof(*cos), "vertexcos1");
- if (r_numVerts) *r_numVerts = numVerts;
- for (i = 0; i < numVerts; i++)
+ if (r_verts_len) *r_verts_len = verts_len;
+ for (i = 0; i < verts_len; i++)
copy_v3_v3(cos[i], me->mvert[i].co);
return cos;
@@ -1046,10 +1249,6 @@ int poly_get_adj_loops_from_vert(
vert);
if (corner != -1) {
-#if 0 /* unused - this loop */
- const MLoop *ml = &mloop[poly->loopstart + corner];
-#endif
-
/* vertex was found */
r_adj[0] = ME_POLY_LOOP_PREV(mloop, poly, corner)->v;
r_adj[1] = ME_POLY_LOOP_NEXT(mloop, poly, corner)->v;
@@ -1072,6 +1271,21 @@ int BKE_mesh_edge_other_vert(const MEdge *e, int v)
return -1;
}
+/**
+ * Sets each output array element to the edge index if it is a real edge, or -1.
+ */
+void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, int r_edges[3])
+{
+ for (int i = 2, i_next = 0; i_next < 3; i = i_next++) {
+ const MLoop *l1 = &mesh->mloop[looptri->tri[i]], *l2 = &mesh->mloop[looptri->tri[i_next]];
+ const MEdge *e = &mesh->medge[l1->e];
+
+ bool is_real = (l1->v == e->v1 && l2->v == e->v2) || (l1->v == e->v2 && l2->v == e->v1);
+
+ r_edges[i] = is_real ? l1->e : -1;
+ }
+}
+
/* basic vertex data functions */
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
{
@@ -1139,13 +1353,13 @@ void BKE_mesh_ensure_navmesh(Mesh *me)
{
if (!CustomData_has_layer(&me->pdata, CD_RECAST)) {
int i;
- int numFaces = me->totpoly;
+ int polys_len = me->totpoly;
int *recastData;
- recastData = (int *)MEM_malloc_arrayN(numFaces, sizeof(int), __func__);
- for (i = 0; i < numFaces; i++) {
+ recastData = (int *)MEM_malloc_arrayN(polys_len, sizeof(int), __func__);
+ for (i = 0; i < polys_len; i++) {
recastData[i] = i + 1;
}
- CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_ASSIGN, recastData, numFaces, "recastData");
+ CustomData_add_layer_named(&me->pdata, CD_RECAST, CD_ASSIGN, recastData, polys_len, "recastData");
}
}
@@ -1337,6 +1551,37 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type)
(me->mselect[me->totselect - 1].type == type));
}
+
+void BKE_mesh_apply_vert_coords(Mesh *mesh, float (*vertCoords)[3])
+{
+ MVert *vert;
+ int i;
+
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ mesh->mvert = vert;
+
+ for (i = 0; i < mesh->totvert; ++i, ++vert)
+ copy_v3_v3(vert->co, vertCoords[i]);
+
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+}
+
+void BKE_mesh_apply_vert_normals(Mesh *mesh, short (*vertNormals)[3])
+{
+ MVert *vert;
+ int i;
+
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert);
+ mesh->mvert = vert;
+
+ for (i = 0; i < mesh->totvert; ++i, ++vert)
+ copy_v3_v3_short(vert->no, vertNormals[i]);
+
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+}
+
/**
* Compute 'split' (aka loop, or per face corner's) normals.
*
@@ -1388,6 +1633,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
if (free_polynors) {
MEM_freeN(polynors);
}
+
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_split(Mesh *mesh)
@@ -1421,25 +1668,25 @@ static int split_faces_prepare_new_verts(
* dealing with smooth/flat faces one can find cases that no simple algorithm can handle properly. */
BLI_assert(lnors_spacearr != NULL);
- const int num_loops = mesh->totloop;
- int num_verts = mesh->totvert;
+ const int loops_len = mesh->totloop;
+ int verts_len = mesh->totvert;
MVert *mvert = mesh->mvert;
MLoop *mloop = mesh->mloop;
- BLI_bitmap *verts_used = BLI_BITMAP_NEW(num_verts, __func__);
- BLI_bitmap *done_loops = BLI_BITMAP_NEW(num_loops, __func__);
+ BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__);
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__);
MLoop *ml = mloop;
MLoopNorSpace **lnor_space = lnors_spacearr->lspacearr;
BLI_assert(lnors_spacearr->data_type == MLNOR_SPACEARR_LOOP_INDEX);
- for (int loop_idx = 0; loop_idx < num_loops; loop_idx++, ml++, lnor_space++) {
+ for (int loop_idx = 0; loop_idx < loops_len; loop_idx++, ml++, lnor_space++) {
if (!BLI_BITMAP_TEST(done_loops, loop_idx)) {
const int vert_idx = ml->v;
const bool vert_used = BLI_BITMAP_TEST_BOOL(verts_used, vert_idx);
/* If vert is already used by another smooth fan, we need a new vert for this one. */
- const int new_vert_idx = vert_used ? num_verts++ : vert_idx;
+ const int new_vert_idx = vert_used ? verts_len++ : vert_idx;
BLI_assert(*lnor_space);
@@ -1484,7 +1731,7 @@ static int split_faces_prepare_new_verts(
MEM_freeN(done_loops);
MEM_freeN(verts_used);
- return num_verts - mesh->totvert;
+ return verts_len - mesh->totvert;
}
/* Detect needed new edges, and update accordingly loops' edge indices.
@@ -1552,12 +1799,12 @@ static int split_faces_prepare_new_edges(
static void split_faces_split_new_verts(
Mesh *mesh, SplitFaceNewVert *new_verts, const int num_new_verts)
{
- const int num_verts = mesh->totvert - num_new_verts;
+ const int verts_len = mesh->totvert - num_new_verts;
MVert *mvert = mesh->mvert;
/* Remember new_verts is a single linklist, so its items are in reversed order... */
MVert *new_mv = &mvert[mesh->totvert - 1];
- for (int i = mesh->totvert - 1; i >= num_verts ; i--, new_mv--, new_verts = new_verts->next) {
+ for (int i = mesh->totvert - 1; i >= verts_len ; i--, new_mv--, new_verts = new_verts->next) {
BLI_assert(new_verts->new_index == i);
BLI_assert(new_verts->new_index != new_verts->orig_index);
CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
@@ -1652,14 +1899,13 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
#endif
}
-
/* **** Depsgraph evaluation **** */
void BKE_mesh_eval_geometry(
- EvaluationContext *UNUSED(eval_ctx),
+ Depsgraph *depsgraph,
Mesh *mesh)
{
- DEG_debug_print_eval(__func__, mesh->id.name, mesh);
+ DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) {
BKE_mesh_texspace_calc(mesh);
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index bfee7f3924c..eed02dae824 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -22,9 +22,11 @@
* \ingroup bke
*/
+
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
+#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
@@ -39,24 +41,33 @@
#include "BKE_main.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_key.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
#include "BKE_displist.h"
#include "BKE_library.h"
#include "BKE_material.h"
-#include "BKE_modifier.h"
#include "BKE_mball.h"
-#include "BKE_depsgraph.h"
+/* these 2 are only used by conversion functions */
#include "BKE_curve.h"
/* -- */
#include "BKE_object.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
/* Define for cases when you want extra validation of mesh
* after certain modifications.
*/
// #undef VALIDATE_MESH
+#ifdef VALIDATE_MESH
+# define ASSERT_IS_VALID_MESH(mesh) (BLI_assert((mesh == NULL) || (BKE_mesh_is_valid(mesh) == true)))
+#else
+# define ASSERT_IS_VALID_MESH(mesh)
+#endif
+
void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
{
DispList *dl;
@@ -206,8 +217,8 @@ int BKE_mesh_nurbs_to_mdata(
{
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
return BKE_mesh_nurbs_displist_to_mdata(
@@ -480,13 +491,65 @@ int BKE_mesh_nurbs_displist_to_mdata(
return 0;
}
+Mesh *BKE_mesh_new_nomain_from_curve_displist(Object *ob, ListBase *dispbase)
+{
+ Curve *cu = ob->data;
+ Mesh *mesh;
+ MVert *allvert;
+ MEdge *alledge;
+ MLoop *allloop;
+ MPoly *allpoly;
+ MLoopUV *alluv = NULL;
+ int totvert, totedge, totloop, totpoly;
+ bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
+
+ if (BKE_mesh_nurbs_displist_to_mdata(
+ ob, dispbase, &allvert, &totvert, &alledge,
+ &totedge, &allloop, &allpoly, (use_orco_uv) ? &alluv : NULL,
+ &totloop, &totpoly) != 0)
+ {
+ /* Error initializing mdata. This often happens when curve is empty */
+ return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
+ }
+
+ mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly);
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ memcpy(mesh->mvert, allvert, totvert * sizeof(MVert));
+ memcpy(mesh->medge, alledge, totedge * sizeof(MEdge));
+ memcpy(mesh->mloop, allloop, totloop * sizeof(MLoop));
+ memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly));
+
+ if (alluv) {
+ const char *uvname = "Orco";
+ CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname);
+ }
+
+ MEM_freeN(allvert);
+ MEM_freeN(alledge);
+ MEM_freeN(allloop);
+ MEM_freeN(allpoly);
+
+ return mesh;
+}
+
+Mesh *BKE_mesh_new_nomain_from_curve(Object *ob)
+{
+ ListBase disp = {NULL, NULL};
+
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
+ }
+
+ return BKE_mesh_new_nomain_from_curve_displist(ob, &disp);
+}
/* this may fail replacing ob->data, be sure to check ob->type */
void BKE_mesh_from_nurbs_displist(
- Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name)
+ Main *bmain, Object *ob, ListBase *dispbase, const bool use_orco_uv, const char *obdata_name, bool temporary)
{
Object *ob1;
- DerivedMesh *dm = ob->derivedFinal;
+ Mesh *me_eval = ob->runtime.mesh_eval;
Mesh *me;
Curve *cu;
MVert *allvert = NULL;
@@ -498,7 +561,7 @@ void BKE_mesh_from_nurbs_displist(
cu = ob->data;
- if (dm == NULL) {
+ if (me_eval == NULL) {
if (BKE_mesh_nurbs_displist_to_mdata(
ob, dispbase, &allvert, &totvert,
&alledge, &totedge, &allloop,
@@ -523,7 +586,6 @@ void BKE_mesh_from_nurbs_displist(
if (alluv) {
const char *uvname = "Orco";
- me->mtpoly = CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname);
me->mloopuv = CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname);
}
@@ -531,7 +593,8 @@ void BKE_mesh_from_nurbs_displist(
}
else {
me = BKE_mesh_add(bmain, obdata_name);
- DM_to_mesh(dm, me, ob, CD_MASK_MESH, false);
+ ob->runtime.mesh_eval = NULL;
+ BKE_mesh_nomain_to_mesh(me_eval, me, ob, CD_MASK_MESH, false);
}
me->totcol = cu->totcol;
@@ -570,7 +633,16 @@ void BKE_mesh_from_nurbs_displist(
ob1 = ob1->id.next;
}
- BKE_libblock_free_us(bmain, cu);
+ if (temporary) {
+ /* For temporary objects in BKE_mesh_new_from_object don't remap
+ * the entire scene with associated depsgraph updates, which are
+ * problematic for renderers exporting data. */
+ id_us_min(&cu->id);
+ BKE_libblock_free(bmain, cu);
+ }
+ else {
+ BKE_libblock_free_us(bmain, cu);
+ }
}
void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
@@ -579,11 +651,11 @@ void BKE_mesh_from_nurbs(Main *bmain, Object *ob)
bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0;
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
- BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name);
+ BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false);
}
typedef struct EdgeLink {
@@ -610,15 +682,15 @@ static void appendPolyLineVert(ListBase *lb, unsigned int index)
BLI_addtail(lb, vl);
}
-void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int edge_users_test)
+void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int edge_users_test)
{
- MVert *mvert = dm->getVertArray(dm);
- MEdge *med, *medge = dm->getEdgeArray(dm);
- MPoly *mp, *mpoly = dm->getPolyArray(dm);
- MLoop *mloop = dm->getLoopArray(dm);
+ MVert *mvert = me->mvert;
+ MEdge *med, *medge = me->medge;
+ MPoly *mp, *mpoly = me->mpoly;
+ MLoop *mloop = me->mloop;
- int dm_totedge = dm->getNumEdges(dm);
- int dm_totpoly = dm->getNumPolys(dm);
+ int medge_len = me->totedge;
+ int mpoly_len = me->totpoly;
int totedges = 0;
int i;
@@ -628,8 +700,8 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
ListBase edges = {NULL, NULL};
/* get boundary edges */
- edge_users = MEM_calloc_arrayN(dm_totedge, sizeof(int), __func__);
- for (i = 0, mp = mpoly; i < dm_totpoly; i++, mp++) {
+ edge_users = MEM_calloc_arrayN(medge_len, sizeof(int), __func__);
+ for (i = 0, mp = mpoly; i < mpoly_len; i++, mp++) {
MLoop *ml = &mloop[mp->loopstart];
int j;
for (j = 0; j < mp->totloop; j++, ml++) {
@@ -639,7 +711,7 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
/* create edges from all faces (so as to find edges not in any faces) */
med = medge;
- for (i = 0; i < dm_totedge; i++, med++) {
+ for (i = 0; i < medge_len; i++, med++) {
if (edge_users[i] == edge_users_test) {
EdgeLink *edl = MEM_callocN(sizeof(EdgeLink), "EdgeLink");
edl->edge = med;
@@ -743,15 +815,14 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
}
}
-void BKE_mesh_to_curve(Main *bmain, Scene *scene, Object *ob)
+void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
/* make new mesh data from the original copy */
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_MESH);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob, CD_MASK_MESH);
ListBase nurblist = {NULL, NULL};
- bool needsFree = false;
- BKE_mesh_to_curve_nurblist(dm, &nurblist, 0);
- BKE_mesh_to_curve_nurblist(dm, &nurblist, 1);
+ BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 0);
+ BKE_mesh_to_curve_nurblist(me_eval, &nurblist, 1);
if (nurblist.first) {
Curve *cu = BKE_curve_add(bmain, ob->id.name + 2, OB_CURVE);
@@ -763,33 +834,19 @@ void BKE_mesh_to_curve(Main *bmain, Scene *scene, Object *ob)
ob->data = cu;
ob->type = OB_CURVE;
- /* curve objects can't contain DM in usual cases, we could free memory */
- needsFree = true;
- }
-
- dm->needsFree = needsFree;
- dm->release(dm);
-
- if (needsFree) {
- ob->derivedFinal = NULL;
-
- /* curve object could have got bounding box only in special cases */
- if (ob->bb) {
- MEM_freeN(ob->bb);
- ob->bb = NULL;
- }
+ BKE_object_free_derived_caches(ob);
}
}
/* settings: 1 - preview, 2 - render */
Mesh *BKE_mesh_new_from_object(
- Main *bmain, Scene *sce, Object *ob,
- int apply_modifiers, int settings, int calc_tessface, int calc_undeformed)
+ Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob,
+ const bool apply_modifiers, const bool calc_undeformed)
{
Mesh *tmpmesh;
Curve *tmpcu = NULL, *copycu;
int i;
- const bool render = (settings == eModifierMode_Render);
+ const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const bool cage = !apply_modifiers;
bool do_mat_id_data_us = true;
@@ -800,15 +857,14 @@ Mesh *BKE_mesh_new_from_object(
case OB_SURF:
{
ListBase dispbase = {NULL, NULL};
- DerivedMesh *derivedFinal = NULL;
+ Mesh *me_eval_final = NULL;
int uv_from_orco;
/* copies object and modifiers (but not the data) */
Object *tmpobj;
/* TODO: make it temp copy outside bmain! */
- BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES, false);
+ BKE_id_copy_ex(bmain, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_CACHES | LIB_ID_CREATE_NO_DEG_TAG, false);
tmpcu = (Curve *)tmpobj->data;
- id_us_min(&tmpcu->id);
/* Copy cached display list, it might be needed by the stack evaluation.
* Ideally stack should be able to use render-time display list, but doing
@@ -816,11 +872,11 @@ Mesh *BKE_mesh_new_from_object(
*
* TODO(sergey): Look into more proper solution.
*/
- if (ob->curve_cache != NULL) {
- if (tmpobj->curve_cache == NULL) {
- tmpobj->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
+ if (ob->runtime.curve_cache != NULL) {
+ if (tmpobj->runtime.curve_cache == NULL) {
+ tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
}
- BKE_displist_copy(&tmpobj->curve_cache->disp, &ob->curve_cache->disp);
+ BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &ob->runtime.curve_cache->disp);
}
/* if getting the original caged mesh, delete object modifiers */
@@ -828,7 +884,8 @@ Mesh *BKE_mesh_new_from_object(
BKE_object_free_modifiers(tmpobj, 0);
/* copies the data */
- copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data);
+ BKE_id_copy_ex(bmain, ob->data, (ID **)&copycu, LIB_ID_CREATE_NO_DEG_TAG, false);
+ tmpobj->data = copycu;
/* make sure texture space is calculated for a copy of curve,
* it will be used for the final result.
@@ -842,16 +899,16 @@ Mesh *BKE_mesh_new_from_object(
copycu->editnurb = tmpcu->editnurb;
/* get updated display list, and convert to a mesh */
- BKE_displist_make_curveTypes_forRender(sce, tmpobj, &dispbase, &derivedFinal, false, render);
+ BKE_displist_make_curveTypes_forRender(depsgraph, sce, tmpobj, &dispbase, &me_eval_final, false, render);
copycu->editfont = NULL;
copycu->editnurb = NULL;
- tmpobj->derivedFinal = derivedFinal;
+ tmpobj->runtime.mesh_eval = me_eval_final;
/* convert object type to mesh */
uv_from_orco = (tmpcu->flag & CU_UV_ORCO) != 0;
- BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2);
+ BKE_mesh_from_nurbs_displist(bmain, tmpobj, &dispbase, uv_from_orco, tmpcu->id.name + 2, true);
tmpmesh = tmpobj->data;
@@ -861,11 +918,11 @@ Mesh *BKE_mesh_new_from_object(
* if it didn't the curve did not have any segments or otherwise
* would have generated an empty mesh */
if (tmpobj->type != OB_MESH) {
- BKE_libblock_free_us(bmain, tmpobj);
+ BKE_libblock_free(bmain, tmpobj);
return NULL;
}
- BKE_libblock_free_us(bmain, tmpobj);
+ BKE_libblock_free(bmain, tmpobj);
/* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist()
* already transfers the ownership of materials from the temp copy of the Curve ID to the new
@@ -878,7 +935,7 @@ Mesh *BKE_mesh_new_from_object(
case OB_MBALL:
{
/* metaballs don't have modifiers, so just convert to mesh */
- Object *basis_ob = BKE_mball_basis_find(bmain, bmain->eval_ctx, sce, ob);
+ Object *basis_ob = BKE_mball_basis_find(sce, ob);
/* todo, re-generatre for render-res */
/* metaball_polygonize(scene, ob) */
@@ -891,20 +948,14 @@ Mesh *BKE_mesh_new_from_object(
if (render) {
ListBase disp = {NULL, NULL};
- /* TODO(sergey): This is gonna to work for until EvaluationContext
- * only contains for_render flag. As soon as CoW is
- * implemented, this is to be rethought.
- */
- EvaluationContext eval_ctx;
- DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER);
- BKE_displist_make_mball_forRender(bmain, &eval_ctx, sce, ob, &disp);
+ BKE_displist_make_mball_forRender(depsgraph, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
}
else {
ListBase disp = {NULL, NULL};
- if (ob->curve_cache) {
- disp = ob->curve_cache->disp;
+ if (ob->runtime.curve_cache) {
+ disp = ob->runtime.curve_cache->disp;
}
BKE_mesh_from_metaball(&disp, tmpmesh);
}
@@ -926,7 +977,7 @@ Mesh *BKE_mesh_new_from_object(
/* if not getting the original caged mesh, get final derived mesh */
else {
/* Make a dummy mesh, saves copying */
- DerivedMesh *dm;
+ Mesh *me_eval;
/* CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL; */
CustomDataMask mask = CD_MASK_MESH; /* this seems more suitable, exporter,
* for example, needs CD_MASK_MDEFORMVERT */
@@ -934,14 +985,15 @@ Mesh *BKE_mesh_new_from_object(
if (calc_undeformed)
mask |= CD_MASK_ORCO;
- /* Write the display mesh into the dummy mesh */
- if (render)
- dm = mesh_create_derived_render(sce, ob, mask);
- else
- dm = mesh_create_derived_view(sce, ob, mask);
+ if (render) {
+ me_eval = mesh_create_eval_final_render(depsgraph, sce, ob, mask);
+ }
+ else {
+ me_eval = mesh_create_eval_final_view(depsgraph, sce, ob, mask);
+ }
tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
- DM_to_mesh(dm, tmpmesh, ob, mask, true);
+ BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, ob, mask, true);
/* Copy autosmooth settings from original mesh. */
Mesh *me = (Mesh *)ob->data;
@@ -1019,10 +1071,345 @@ Mesh *BKE_mesh_new_from_object(
break;
} /* end copy materials */
- if (calc_tessface) {
- /* cycles and exporters rely on this still */
- BKE_mesh_tessface_ensure(tmpmesh);
+ return tmpmesh;
+}
+
+
+static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src)
+{
+ KeyBlock *kb;
+ Key *key = mesh_src->key;
+ int i;
+
+ if (!mesh_src->key)
+ return;
+
+ /* ensure we can use mesh vertex count for derived mesh custom data */
+ if (mesh_src->totvert != mesh_dest->totvert) {
+ fprintf(stderr,
+ "%s: vertex size mismatch (mesh/dm) '%s' (%d != %d)\n",
+ __func__, mesh_src->id.name + 2, mesh_src->totvert, mesh_dest->totvert);
+ return;
}
- return tmpmesh;
+ for (i = 0, kb = key->block.first; kb; kb = kb->next, i++) {
+ int ci;
+ float *array;
+
+ if (mesh_src->totvert != kb->totelem) {
+ fprintf(stderr,
+ "%s: vertex size mismatch (Mesh '%s':%d != KeyBlock '%s':%d)\n",
+ __func__, mesh_src->id.name + 2, mesh_src->totvert, kb->name, kb->totelem);
+ array = MEM_calloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
+ }
+ else {
+ array = MEM_malloc_arrayN((size_t)mesh_src->totvert, 3 * sizeof(float), __func__);
+ memcpy(array, kb->data, (size_t)mesh_src->totvert * 3 * sizeof(float));
+ }
+
+ CustomData_add_layer_named(&mesh_dest->vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest->totvert, kb->name);
+ ci = CustomData_get_layer_index_n(&mesh_dest->vdata, CD_SHAPEKEY, i);
+
+ mesh_dest->vdata.layers[ci].uid = kb->uid;
+ }
+}
+
+
+Mesh *BKE_mesh_create_derived_for_modifier(
+ struct Depsgraph *depsgraph, Scene *scene, Object *ob,
+ ModifierData *md, int build_shapekey_layers)
+{
+ Mesh *me = ob->data;
+ const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ Mesh *result;
+ KeyBlock *kb;
+ ModifierEvalContext mectx = {depsgraph, ob, 0};
+
+ if (!(md->mode & eModifierMode_Realtime)) {
+ return NULL;
+ }
+
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) {
+ return NULL;
+ }
+
+ if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) {
+ BKE_keyblock_convert_to_mesh(kb, me);
+ }
+
+ if (mti->type == eModifierTypeType_OnlyDeform) {
+ int numVerts;
+ float (*deformedVerts)[3] = BKE_mesh_vertexCos_get(me, &numVerts);
+
+ mti->deformVerts(md, &mectx, NULL, deformedVerts, numVerts);
+ BKE_id_copy_ex(
+ NULL, &me->id, (ID **)&result,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ BKE_mesh_apply_vert_coords(result, deformedVerts);
+
+ if (build_shapekey_layers)
+ add_shapekey_layers(result, me);
+
+ MEM_freeN(deformedVerts);
+ }
+ else {
+ Mesh *mesh_temp;
+ BKE_id_copy_ex(
+ NULL, &me->id, (ID **)&mesh_temp,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+
+ if (build_shapekey_layers)
+ add_shapekey_layers(mesh_temp, me);
+
+ result = mti->applyModifier(md, &mectx, mesh_temp);
+ ASSERT_IS_VALID_MESH(result);
+
+ if (mesh_temp != result) {
+ BKE_id_free(NULL, mesh_temp);
+ }
+ }
+
+ return result;
+}
+
+/* This is a Mesh-based copy of the same function in DerivedMesh.c */
+static void shapekey_layers_to_keyblocks(Mesh *mesh_src, Mesh *mesh_dst, int actshape_uid)
+{
+ KeyBlock *kb;
+ int i, j, tot;
+
+ if (!mesh_dst->key)
+ return;
+
+ tot = CustomData_number_of_layers(&mesh_src->vdata, CD_SHAPEKEY);
+ for (i = 0; i < tot; i++) {
+ CustomDataLayer *layer = &mesh_src->vdata.layers[CustomData_get_layer_index_n(&mesh_src->vdata, CD_SHAPEKEY, i)];
+ float (*cos)[3], (*kbcos)[3];
+
+ for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ if (kb->uid == layer->uid)
+ break;
+ }
+
+ if (!kb) {
+ kb = BKE_keyblock_add(mesh_dst->key, layer->name);
+ kb->uid = layer->uid;
+ }
+
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ cos = CustomData_get_layer_n(&mesh_src->vdata, CD_SHAPEKEY, i);
+ kb->totelem = mesh_src->totvert;
+
+ kb->data = kbcos = MEM_malloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
+ if (kb->uid == actshape_uid) {
+ MVert *mvert = mesh_src->mvert;
+
+ for (j = 0; j < mesh_src->totvert; j++, kbcos++, mvert++) {
+ copy_v3_v3(*kbcos, mvert->co);
+ }
+ }
+ else {
+ for (j = 0; j < kb->totelem; j++, cos++, kbcos++) {
+ copy_v3_v3(*kbcos, *cos);
+ }
+ }
+ }
+
+ for (kb = mesh_dst->key->block.first; kb; kb = kb->next) {
+ if (kb->totelem != mesh_src->totvert) {
+ if (kb->data)
+ MEM_freeN(kb->data);
+
+ kb->totelem = mesh_src->totvert;
+ kb->data = MEM_calloc_arrayN(kb->totelem, 3 * sizeof(float), __func__);
+ fprintf(stderr, "%s: lost a shapekey layer: '%s'! (bmesh internal error)\n", __func__, kb->name);
+ }
+ }
+}
+
+
+/* This is a Mesh-based copy of DM_to_mesh() */
+void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, CustomDataMask mask, bool take_ownership)
+{
+ /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
+ /* TODO(Sybren): the above claim came from DM_to_mesh(); check whether it is still true with Mesh */
+ Mesh tmp = *mesh_dst;
+ int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
+ int did_shapekeys = 0;
+ eCDAllocType alloctype = CD_DUPLICATE;
+
+ if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) {
+ bool has_any_referenced_layers =
+ CustomData_has_referenced(&mesh_src->vdata) ||
+ CustomData_has_referenced(&mesh_src->edata) ||
+ CustomData_has_referenced(&mesh_src->ldata) ||
+ CustomData_has_referenced(&mesh_src->fdata) ||
+ CustomData_has_referenced(&mesh_src->pdata);
+ if (!has_any_referenced_layers) {
+ alloctype = CD_ASSIGN;
+ }
+ }
+ CustomData_reset(&tmp.vdata);
+ CustomData_reset(&tmp.edata);
+ CustomData_reset(&tmp.fdata);
+ CustomData_reset(&tmp.ldata);
+ CustomData_reset(&tmp.pdata);
+
+ BKE_mesh_ensure_normals(mesh_src);
+
+ totvert = tmp.totvert = mesh_src->totvert;
+ totedge = tmp.totedge = mesh_src->totedge;
+ totloop = tmp.totloop = mesh_src->totloop;
+ totpoly = tmp.totpoly = mesh_src->totpoly;
+ tmp.totface = 0;
+
+ CustomData_copy(&mesh_src->vdata, &tmp.vdata, mask, alloctype, totvert);
+ CustomData_copy(&mesh_src->edata, &tmp.edata, mask, alloctype, totedge);
+ CustomData_copy(&mesh_src->ldata, &tmp.ldata, mask, alloctype, totloop);
+ CustomData_copy(&mesh_src->pdata, &tmp.pdata, mask, alloctype, totpoly);
+ tmp.cd_flag = mesh_src->cd_flag;
+ tmp.runtime.deformed_only = mesh_src->runtime.deformed_only;
+
+ if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
+ KeyBlock *kb;
+ int uid;
+
+ if (ob) {
+ kb = BLI_findlink(&mesh_dst->key->block, ob->shapenr - 1);
+ if (kb) {
+ uid = kb->uid;
+ }
+ else {
+ printf("%s: error - could not find active shapekey %d!\n",
+ __func__, ob->shapenr - 1);
+
+ uid = INT_MAX;
+ }
+ }
+ else {
+ /* if no object, set to INT_MAX so we don't mess up any shapekey layers */
+ uid = INT_MAX;
+ }
+
+ shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid);
+ did_shapekeys = 1;
+ }
+
+ /* copy texture space */
+ if (ob) {
+ BKE_mesh_texspace_copy_from_object(&tmp, ob);
+ }
+
+ /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
+ * we set them here in case they are missing */
+ /* TODO(Sybren): we could probably replace CD_ASSIGN with alloctype and always directly pass mesh_src->mxxx,
+ * instead of using a ternary operator. */
+ if (!CustomData_has_layer(&tmp.vdata, CD_MVERT)) {
+ CustomData_add_layer(
+ &tmp.vdata, CD_MVERT, CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->mvert : MEM_dupallocN(mesh_src->mvert),
+ totvert);
+ }
+ if (!CustomData_has_layer(&tmp.edata, CD_MEDGE)) {
+ CustomData_add_layer(
+ &tmp.edata, CD_MEDGE, CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->medge : MEM_dupallocN(mesh_src->medge),
+ totedge);
+ }
+ if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
+ /* TODO(Sybren): assignment to tmp.mxxx is probably not necessary due to the
+ * BKE_mesh_update_customdata_pointers() call below. */
+ tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop);
+ tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly);
+
+ CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
+ CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
+ }
+
+ /* object had got displacement layer, should copy this layer to save sculpted data */
+ /* NOTE: maybe some other layers should be copied? nazgul */
+ if (CustomData_has_layer(&mesh_dst->ldata, CD_MDISPS)) {
+ if (totloop == mesh_dst->totloop) {
+ MDisps *mdisps = CustomData_get_layer(&mesh_dst->ldata, CD_MDISPS);
+ CustomData_add_layer(&tmp.ldata, CD_MDISPS, alloctype, mdisps, totloop);
+ }
+ }
+
+ /* yes, must be before _and_ after tessellate */
+ BKE_mesh_update_customdata_pointers(&tmp, false);
+
+ /* since 2.65 caller must do! */
+ // BKE_mesh_tessface_calc(&tmp);
+
+ CustomData_free(&mesh_dst->vdata, mesh_dst->totvert);
+ CustomData_free(&mesh_dst->edata, mesh_dst->totedge);
+ CustomData_free(&mesh_dst->fdata, mesh_dst->totface);
+ CustomData_free(&mesh_dst->ldata, mesh_dst->totloop);
+ CustomData_free(&mesh_dst->pdata, mesh_dst->totpoly);
+
+ /* ok, this should now use new CD shapekey data,
+ * which should be fed through the modifier
+ * stack */
+ if (tmp.totvert != mesh_dst->totvert && !did_shapekeys && mesh_dst->key) {
+ printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name);
+ if (tmp.key && !(tmp.id.tag & LIB_TAG_NO_MAIN)) {
+ id_us_min(&tmp.key->id);
+ }
+ tmp.key = NULL;
+ }
+
+ /* Clear selection history */
+ MEM_SAFE_FREE(tmp.mselect);
+ tmp.totselect = 0;
+ BLI_assert(ELEM(tmp.bb, NULL, mesh_dst->bb));
+ if (mesh_dst->bb) {
+ MEM_freeN(mesh_dst->bb);
+ tmp.bb = NULL;
+ }
+
+ /* skip the listbase */
+ MEMCPY_STRUCT_OFS(mesh_dst, &tmp, id.prev);
+
+ if (take_ownership) {
+ if (alloctype == CD_ASSIGN) {
+ CustomData_free_typemask(&mesh_src->vdata, mesh_src->totvert, ~mask);
+ CustomData_free_typemask(&mesh_src->edata, mesh_src->totedge, ~mask);
+ CustomData_free_typemask(&mesh_src->ldata, mesh_src->totloop, ~mask);
+ CustomData_free_typemask(&mesh_src->pdata, mesh_src->totpoly, ~mask);
+ }
+ BKE_id_free(NULL, mesh_src);
+ }
+}
+
+/* This is a Mesh-based copy of DM_to_meshkey() */
+void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
+{
+ int a, totvert = mesh_src->totvert;
+ float *fp;
+ MVert *mvert;
+
+ if (totvert == 0 || mesh_dst->totvert == 0 || mesh_dst->totvert != totvert) {
+ return;
+ }
+
+ if (kb->data) MEM_freeN(kb->data);
+ kb->data = MEM_malloc_arrayN(mesh_dst->key->elemsize, mesh_dst->totvert, "kb->data");
+ kb->totelem = totvert;
+
+ fp = kb->data;
+ mvert = mesh_src->mvert;
+
+ for (a = 0; a < kb->totelem; a++, fp += 3, mvert++) {
+ copy_v3_v3(fp, mvert->co);
+ }
}
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index e3b1f20e583..fd117734aaf 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -88,6 +88,20 @@ static void mesh_calc_normals_vert_fallback(MVert *mverts, int numVerts)
}
}
+/* TODO(Sybren): we can probably rename this to BKE_mesh_calc_normals_mapping(),
+ * and remove the function of the same name below, as that one doesn't seem to be
+ * called anywhere. */
+void BKE_mesh_calc_normals_mapping_simple(struct Mesh *mesh)
+{
+ const bool only_face_normals = CustomData_is_referenced_layer(&mesh->vdata, CD_MVERT);
+
+ BKE_mesh_calc_normals_mapping_ex(
+ mesh->mvert, mesh->totvert,
+ mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL,
+ mesh->mface, mesh->totface, NULL, NULL,
+ only_face_normals);
+}
+
/* Calculate vertex and face normals, face normals are returned in *r_faceNors if non-NULL
* and vertex normals are stored in actual mverts.
*/
@@ -332,6 +346,44 @@ void BKE_mesh_calc_normals_poly(
MEM_freeN(lnors_weighted);
}
+void BKE_mesh_ensure_normals(Mesh *mesh)
+{
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
+ BKE_mesh_calc_normals(mesh);
+ }
+ BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
+}
+
+/**
+ * Called after calculating all modifiers.
+ */
+void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
+{
+ /* Note: mesh *may* have a poly CD_NORMAL layer (generated by a modifier needing poly normals e.g.).
+ * We do not use it here, though. And it should be tagged as temp!
+ */
+ /* BLI_assert((CustomData_has_layer(&mesh->pdata, CD_NORMAL) == false)); */
+
+ if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL || !CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
+ float (*poly_nors)[3] = NULL;
+ poly_nors = MEM_malloc_arrayN((size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
+
+ /* if normals are dirty we want to calculate vertex normals too */
+ bool only_face_normals = !(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL);
+
+ /* calculate face normals */
+ BKE_mesh_calc_normals_poly(
+ mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly,
+ mesh->totloop, mesh->totpoly, poly_nors,
+ only_face_normals);
+
+ CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
+
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ }
+}
+
+/* Note that this does not update the CD_NORMAL layer, but does update the normals in the CD_MVERT layer. */
void BKE_mesh_calc_normals(Mesh *mesh)
{
#ifdef DEBUG_TIME
@@ -344,6 +396,7 @@ void BKE_mesh_calc_normals(Mesh *mesh)
#ifdef DEBUG_TIME
TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_tessface(
@@ -456,6 +509,8 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo
mem = lnors_spacearr->mem;
lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops);
lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
+
+ lnors_spacearr->num_spaces = 0;
}
BLI_assert(ELEM(data_type, MLNOR_SPACEARR_BMLOOP_PTR, MLNOR_SPACEARR_LOOP_INDEX));
lnors_spacearr->data_type = data_type;
@@ -463,21 +518,24 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoo
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
{
- BLI_memarena_clear(lnors_spacearr->mem);
+ lnors_spacearr->num_spaces = 0;
lnors_spacearr->lspacearr = NULL;
lnors_spacearr->loops_pool = NULL;
+ BLI_memarena_clear(lnors_spacearr->mem);
}
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
{
- BLI_memarena_free(lnors_spacearr->mem);
+ lnors_spacearr->num_spaces = 0;
lnors_spacearr->lspacearr = NULL;
lnors_spacearr->loops_pool = NULL;
+ BLI_memarena_free(lnors_spacearr->mem);
lnors_spacearr->mem = NULL;
}
MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
{
+ lnors_spacearr->num_spaces++;
return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace));
}
@@ -1835,155 +1893,6 @@ void BKE_mesh_normals_loop_to_vertex(
/* -------------------------------------------------------------------- */
-/** \name Mesh Tangent Calculations
- * \{ */
-
-/* Tangent space utils. */
-
-/* User data. */
-typedef struct {
- const MPoly *mpolys; /* faces */
- const MLoop *mloops; /* faces's vertices */
- const MVert *mverts; /* vertices */
- const MLoopUV *luvs; /* texture coordinates */
- float (*lnors)[3]; /* loops' normals */
- float (*tangents)[4]; /* output tangents */
- int num_polys; /* number of polygons */
-} BKEMeshToTangent;
-
-/* Mikktspace's API */
-static int get_num_faces(const SMikkTSpaceContext *pContext)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- return p_mesh->num_polys;
-}
-
-static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- return p_mesh->mpolys[face_idx].totloop;
-}
-
-static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
- copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
-}
-
-static void get_texture_coordinate(
- const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx,
- const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
-}
-
-static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
-}
-
-static void set_tspace(
- const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign,
- const int face_idx, const int vert_idx)
-{
- BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
- float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
- copy_v3_v3(p_res, fv_tangent);
- p_res[3] = face_sign;
-}
-
-/**
- * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
- * split normals can be used to recreate the full tangent space.
- * Note: * The mesh should be made of only tris and quads!
- */
-void BKE_mesh_loop_tangents_ex(
- const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
- float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
- const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
- ReportList *reports)
-{
- BKEMeshToTangent mesh_to_tangent = {NULL};
- SMikkTSpaceContext s_context = {NULL};
- SMikkTSpaceInterface s_interface = {NULL};
-
- const MPoly *mp;
- int mp_index;
-
- /* First check we do have a tris/quads only mesh. */
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- if (mp->totloop > 4) {
- BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
- return;
- }
- }
-
- /* Compute Mikktspace's tangent normals. */
- mesh_to_tangent.mpolys = mpolys;
- mesh_to_tangent.mloops = mloops;
- mesh_to_tangent.mverts = mverts;
- mesh_to_tangent.luvs = loopuvs;
- mesh_to_tangent.lnors = loopnors;
- mesh_to_tangent.tangents = r_looptangent;
- mesh_to_tangent.num_polys = numPolys;
-
- s_context.m_pUserData = &mesh_to_tangent;
- s_context.m_pInterface = &s_interface;
- s_interface.m_getNumFaces = get_num_faces;
- s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
- s_interface.m_getPosition = get_position;
- s_interface.m_getTexCoord = get_texture_coordinate;
- s_interface.m_getNormal = get_normal;
- s_interface.m_setTSpaceBasic = set_tspace;
-
- /* 0 if failed */
- if (genTangSpaceDefault(&s_context) == false) {
- BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
- }
-}
-
-/**
- * Wrapper around BKE_mesh_loop_tangents_ex, which takes care of most boiling code.
- * \note
- * - There must be a valid loop's CD_NORMALS available.
- * - The mesh should be made of only tris and quads!
- */
-void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
-{
- MLoopUV *loopuvs;
- float (*loopnors)[3];
-
- /* Check we have valid texture coordinates first! */
- if (uvmap) {
- loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
- }
- else {
- loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
- }
- if (!loopuvs) {
- BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
- return;
- }
-
- loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- if (!loopnors) {
- BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
- return;
- }
-
- BKE_mesh_loop_tangents_ex(
- mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
- loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-
/** \name Polygon Calculations
* \{ */
@@ -2256,30 +2165,6 @@ static float mesh_calc_poly_area_centroid(
return total_area;
}
-#if 0 /* slow version of the function below */
-void BKE_mesh_calc_poly_angles(
- MPoly *mpoly, MLoop *loopstart,
- MVert *mvarray, float angles[])
-{
- MLoop *ml;
- MLoop *mloop = &loopstart[-mpoly->loopstart];
-
- int j;
- for (j = 0, ml = loopstart; j < mpoly->totloop; j++, ml++) {
- MLoop *ml_prev = ME_POLY_LOOP_PREV(mloop, mpoly, j);
- MLoop *ml_next = ME_POLY_LOOP_NEXT(mloop, mpoly, j);
-
- float e1[3], e2[3];
-
- sub_v3_v3v3(e1, mvarray[ml_next->v].co, mvarray[ml->v].co);
- sub_v3_v3v3(e2, mvarray[ml_prev->v].co, mvarray[ml->v].co);
-
- angles[j] = (float)M_PI - angle_v3v3(e1, e2);
- }
-}
-
-#else /* equivalent the function above but avoid multiple subtractions + normalize */
-
void BKE_mesh_calc_poly_angles(
const MPoly *mpoly, const MLoop *loopstart,
const MVert *mvarray, float angles[])
@@ -2304,7 +2189,6 @@ void BKE_mesh_calc_poly_angles(
i_next++;
}
}
-#endif
void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *mp, const MLoop *mloop)
{
@@ -2556,12 +2440,12 @@ void BKE_mesh_calc_volume(
*/
void BKE_mesh_loops_to_mface_corners(
CustomData *fdata, CustomData *ldata,
- CustomData *pdata, unsigned int lindex[4], int findex,
- const int polyindex,
+ CustomData *UNUSED(pdata), unsigned int lindex[4], int findex,
+ const int UNUSED(polyindex),
const int mf_len, /* 3 or 4 */
/* cache values to avoid lookups every time */
- const int numTex, /* CustomData_number_of_layers(pdata, CD_MTEXPOLY) */
+ const int numUV, /* CustomData_number_of_layers(ldata, CD_MLOOPUV) */
const int numCol, /* CustomData_number_of_layers(ldata, CD_MLOOPCOL) */
const bool hasPCol, /* CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL) */
const bool hasOrigSpace, /* CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP) */
@@ -2569,17 +2453,13 @@ void BKE_mesh_loops_to_mface_corners(
)
{
MTFace *texface;
- MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
int i, j;
- for (i = 0; i < numTex; i++) {
+ for (i = 0; i < numUV; i++) {
texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
- texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
-
- ME_MTEXFACE_CPY(texface, texpoly);
for (j = 0; j < mf_len; j++) {
mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, (int)lindex[j], i);
@@ -2632,14 +2512,14 @@ void BKE_mesh_loops_to_mface_corners(
* \note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used.
*/
void BKE_mesh_loops_to_tessdata(
- CustomData *fdata, CustomData *ldata, CustomData *pdata, MFace *mface,
+ CustomData *fdata, CustomData *ldata, MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
{
/* Note: performances are sub-optimal when we get a NULL mface, we could be ~25% quicker with dedicated code...
* Issue is, unless having two different functions with nearly the same code, there's not much ways to solve
* this. Better imho to live with it for now. :/ --mont29
*/
- const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
+ const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
@@ -2649,17 +2529,14 @@ void BKE_mesh_loops_to_tessdata(
const int *pidx;
unsigned int (*lidx)[4];
- for (i = 0; i < numTex; i++) {
+ for (i = 0; i < numUV; i++) {
MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
- MTexPoly *texpoly = CustomData_get_layer_n(pdata, CD_MTEXPOLY, i);
MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
for (findex = 0, pidx = polyindices, lidx = loopindices;
findex < num_faces;
pidx++, lidx++, findex++, texface++)
{
- ME_MTEXFACE_CPY(texface, &texpoly[*pidx]);
-
for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
}
@@ -2982,7 +2859,7 @@ int BKE_mesh_recalc_tessellation(
/* CD_ORIGINDEX will contain an array of indices from tessfaces to the polygons
* they are directly tessellated from */
CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
- CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
+ CustomData_from_bmeshpoly(fdata, ldata, totface);
if (do_face_nor_copy) {
/* If polys have a normals layer, copying that to faces can help
@@ -3003,7 +2880,7 @@ int BKE_mesh_recalc_tessellation(
* So we pass NULL as MFace pointer, and BKE_mesh_loops_to_tessdata will use the fourth loop index as quad test.
* ...
*/
- BKE_mesh_loops_to_tessdata(fdata, ldata, pdata, NULL, mface_to_poly_map, lindices, totface);
+ BKE_mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
/* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
* ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
@@ -3173,11 +3050,10 @@ void BKE_mesh_recalc_looptri(
}
static void bm_corners_to_loops_ex(
- ID *id, CustomData *fdata, CustomData *ldata, CustomData *pdata,
+ ID *id, CustomData *fdata, CustomData *ldata,
MFace *mface, int totloop, int findex, int loopstart, int numTex, int numCol)
{
MTFace *texface;
- MTexPoly *texpoly;
MCol *mcol;
MLoopCol *mloopcol;
MLoopUV *mloopuv;
@@ -3188,9 +3064,6 @@ static void bm_corners_to_loops_ex(
for (i = 0; i < numTex; i++) {
texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
- texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, findex, i);
-
- ME_MTEXFACE_CPY(texpoly, texface);
mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
copy_v2_v2(mloopuv->uv, texface->uv[0]); mloopuv++;
@@ -3300,7 +3173,7 @@ void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
mesh->medge, mesh->mface,
&mesh->totloop, &mesh->totpoly, &mesh->mloop, &mesh->mpoly);
- CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->pdata, &mesh->ldata);
+ CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
BKE_mesh_update_customdata_pointers(mesh, true);
}
@@ -3344,7 +3217,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(
CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
- CustomData_to_bmeshpoly(fdata, pdata, ldata, totloop, totpoly);
+ CustomData_to_bmeshpoly(fdata, ldata, totloop);
if (id) {
/* ensure external data is transferred */
@@ -3394,7 +3267,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(
# undef ML
- bm_corners_to_loops_ex(id, fdata, ldata, pdata, mface, totloop, i, mp->loopstart, numTex, numCol);
+ bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
if (polyindex) {
*polyindex = i;
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
new file mode 100644
index 00000000000..73dcd912f48
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -0,0 +1,211 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_iterators.c
+ * \ingroup bke
+ *
+ * Functions for iterating mesh features.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+/* Copied from cdDM_foreachMappedVert */
+void BKE_mesh_foreach_mapped_vert(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]),
+ void *userData,
+ MeshForeachFlag flag)
+{
+ const MVert *mv = mesh->mvert;
+ const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv->co, NULL, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totvert; i++, mv++) {
+ const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ func(userData, i, mv->co, NULL, no);
+ }
+ }
+}
+
+/* Copied from cdDM_foreachMappedEdge */
+void BKE_mesh_foreach_mapped_edge(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]),
+ void *userData)
+{
+ const MVert *mv = mesh->mvert;
+ const MEdge *med = mesh->medge;
+ const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ func(userData, orig, mv[med->v1].co, mv[med->v2].co);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ }
+ }
+}
+
+/* Copied from cdDM_foreachMappedLoop */
+void BKE_mesh_foreach_mapped_loop(
+ Mesh *mesh,
+ void (*func)(void *userData, int vertex_index, int face_index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
+{
+ /* We can't use dm->getLoopDataLayout(dm) here, we want to always access dm->loopData, EditDerivedBMesh would
+ * return loop data from bmesh itself. */
+ const float (*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? CustomData_get_layer(&mesh->ldata, CD_NORMAL) : NULL;
+
+ const MVert *mv = mesh->mvert;
+ const MLoop *ml = mesh->mloop;
+ const MPoly *mp = mesh->mpoly;
+ const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+ int p_idx, i;
+
+ if (v_index || f_index) {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = v_index ? v_index[ml->v] : ml->v;
+ const int f_idx = f_index ? f_index[p_idx] : p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
+ continue;
+ }
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
+ else {
+ for (p_idx = 0; p_idx < mesh->totpoly; p_idx++, mp++) {
+ for (i = 0; i < mp->totloop; i++, ml++) {
+ const int v_idx = ml->v;
+ const int f_idx = p_idx;
+ const float *no = lnors ? *lnors++ : NULL;
+ func(userData, v_idx, f_idx, mv[ml->v].co, no);
+ }
+ }
+ }
+}
+
+/* Copied from cdDM_foreachMappedFaceCenter */
+void BKE_mesh_foreach_mapped_face_center(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float cent[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
+{
+ const MVert *mvert = mesh->mvert;
+ const MPoly *mp = mesh->mpoly;
+ const MLoop *ml;
+ float _no_buf[3];
+ float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
+ const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
+
+ if (index) {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ const int orig = *index++;
+ if (orig == ORIGINDEX_NONE) {
+ continue;
+ }
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, orig, cent, no);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totpoly; i++, mp++) {
+ float cent[3];
+ ml = &mesh->mloop[mp->loopstart];
+ BKE_mesh_calc_poly_center(mp, ml, mvert, cent);
+ if (flag & MESH_FOREACH_USE_NORMAL) {
+ BKE_mesh_calc_poly_normal(mp, ml, mvert, no);
+ }
+ func(userData, i, cent, no);
+ }
+ }
+}
+
+
+/* Helpers based on above foreach loopers> */
+
+typedef struct MappedVCosData {
+ float (*vertexcos)[3];
+ BLI_bitmap *vertex_visit;
+} MappedVCosData;
+
+static void get_vertexcos__mapFunc(
+ void *user_data, int index, const float co[3],
+ const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+ MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data;
+
+ if (BLI_BITMAP_TEST(mapped_vcos_data->vertex_visit, index) == 0) {
+ /* We need coord from prototype vertex, not from copies,
+ * we assume they stored in the beginning of vertex array stored in evaluated mesh
+ * (mirror modifier for eg does this). */
+ copy_v3_v3(mapped_vcos_data->vertexcos[index], co);
+ BLI_BITMAP_ENABLE(mapped_vcos_data->vertex_visit, index);
+ }
+}
+
+void BKE_mesh_foreach_mapped_vert_coords_get(Mesh *me_eval, float (*r_cos)[3], const int totcos)
+{
+ MappedVCosData user_data;
+ memset(r_cos, 0, sizeof(*r_cos) * totcos);
+ user_data.vertexcos = r_cos;
+ user_data.vertex_visit = BLI_BITMAP_NEW(totcos, __func__);
+ BKE_mesh_foreach_mapped_vert(me_eval, get_vertexcos__mapFunc, &user_data, MESH_FOREACH_NOP);
+ MEM_freeN(user_data.vertex_visit);
+}
diff --git a/source/blender/blenkernel/intern/mesh_merge.c b/source/blender/blenkernel/intern/mesh_merge.c
new file mode 100644
index 00000000000..5324c397ebf
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_merge.c
@@ -0,0 +1,685 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_merge.c
+ * \ingroup bke
+ */
+#include <string.h> // for memcpy
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_utildefines_stack.h"
+#include "BLI_edgehash.h"
+#include "BLI_ghash.h"
+
+#include "BKE_customdata.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+
+/**
+ * Poly compare with vtargetmap
+ * Function used by #BKE_mesh_merge_verts.
+ * The function compares poly_source after applying vtargetmap, with poly_target.
+ * The two polys are identical if they share the same vertices in the same order, or in reverse order,
+ * but starting position loopstart may be different.
+ * The function is called with direct_reverse=1 for same order (i.e. same normal),
+ * and may be called again with direct_reverse=-1 for reverse order.
+ * \return 1 if polys are identical, 0 if polys are different.
+ */
+static int cddm_poly_compare(
+ MLoop *mloop_array,
+ MPoly *mpoly_source, MPoly *mpoly_target,
+ const int *vtargetmap, const int direct_reverse)
+{
+ int vert_source, first_vert_source, vert_target;
+ int i_loop_source;
+ int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted;
+ bool compare_completed = false;
+ bool same_loops = false;
+
+ MLoop *mloop_source, *mloop_target;
+
+ BLI_assert(direct_reverse == 1 || direct_reverse == -1);
+
+ i_loop_source = 0;
+ mloop_source = mloop_array + mpoly_source->loopstart;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ /* Find same vertex within mpoly_target's loops */
+ mloop_target = mloop_array + mpoly_target->loopstart;
+ for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) {
+ if (mloop_target->v == vert_source) {
+ break;
+ }
+ }
+
+ /* If same vertex not found, then polys cannot be equal */
+ if (i_loop_target >= mpoly_target->totloop) {
+ return false;
+ }
+
+ /* Now mloop_source and m_loop_target have one identical vertex */
+ /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */
+ /* Go around the loop and check that all vertices match in same order */
+ /* Skipping source loops when consecutive source vertices are mapped to same target vertex */
+
+ i_loop_target_start = i_loop_target;
+ i_loop_target_offset = 0;
+ first_vert_source = vert_source;
+
+ compare_completed = false;
+ same_loops = false;
+
+ while (!compare_completed) {
+
+ vert_target = mloop_target->v;
+
+ /* First advance i_loop_source, until it points to different vertex, after mapping applied */
+ do {
+ i_loop_source++;
+
+ if (i_loop_source == mpoly_source->totloop) {
+ /* End of loops for source, must match end of loop for target. */
+ if (i_loop_target_offset == mpoly_target->totloop - 1) {
+ compare_completed = true;
+ same_loops = true;
+ break; /* Polys are identical */
+ }
+ else {
+ compare_completed = true;
+ same_loops = false;
+ break; /* Polys are different */
+ }
+ }
+
+ mloop_source++;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ } while (vert_source == vert_target);
+
+ if (compare_completed) {
+ break;
+ }
+
+ /* Now advance i_loop_target as well */
+ i_loop_target_offset++;
+
+ if (i_loop_target_offset == mpoly_target->totloop) {
+ /* End of loops for target only, that means no match */
+ /* except if all remaining source vertices are mapped to first target */
+ for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) {
+ vert_source = vtargetmap[mloop_source->v];
+ if (vert_source != first_vert_source) {
+ compare_completed = true;
+ same_loops = false;
+ break;
+ }
+ }
+ if (!compare_completed) {
+ same_loops = true;
+ }
+ break;
+ }
+
+ /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */
+ i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop;
+ if (i_loop_target_adjusted < 0) {
+ i_loop_target_adjusted += mpoly_target->totloop;
+ }
+ mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted;
+ vert_target = mloop_target->v;
+
+ if (vert_target != vert_source) {
+ same_loops = false; /* Polys are different */
+ break;
+ }
+ }
+ return same_loops;
+}
+
+
+/* Utility stuff for using GHash with polys, used by vertex merging. */
+
+typedef struct PolyKey {
+ int poly_index; /* index of the MPoly within the derived mesh */
+ int totloops; /* number of loops in the poly */
+ unsigned int hash_sum; /* Sum of all vertices indices */
+ unsigned int hash_xor; /* Xor of all vertices indices */
+} PolyKey;
+
+
+static unsigned int poly_gset_hash_fn(const void *key)
+{
+ const PolyKey *pk = key;
+ return pk->hash_sum;
+}
+
+static bool poly_gset_compare_fn(const void *k1, const void *k2)
+{
+ const PolyKey *pk1 = k1;
+ const PolyKey *pk2 = k2;
+ if ((pk1->hash_sum == pk2->hash_sum) &&
+ (pk1->hash_xor == pk2->hash_xor) &&
+ (pk1->totloops == pk2->totloops))
+ {
+ /* Equality - note that this does not mean equality of polys */
+ return false;
+ }
+ else {
+ return true;
+ }
+}
+
+/**
+ * Merge Verts
+ *
+ * This frees the given mesh and returns a new mesh.
+ *
+ * \param vtargetmap The table that maps vertices to target vertices. a value of -1
+ * indicates a vertex is a target, and is to be kept.
+ * This array is aligned with 'mesh->totvert'
+ * \warning \a vtargetmap must **not** contain any chained mapping (v1 -> v2 -> v3 etc.), this is not supported
+ * and will likely generate corrupted geometry.
+ *
+ * \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size)
+ *
+ * \param merge_mode enum with two modes.
+ * - #MESH_MERGE_VERTS_DUMP_IF_MAPPED
+ * When called by the Mirror Modifier,
+ * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
+ * of faces sharing the same set of vertices)
+ * - #MESH_MERGE_VERTS_DUMP_IF_EQUAL
+ * When called by the Array Modifier,
+ * In this mode, faces where all vertices are merged are double-checked,
+ * to see whether all target vertices actually make up a poly already.
+ * Indeed it could be that all of a poly's vertices are merged,
+ * but merged to vertices that do not make up a single poly,
+ * in which case the original poly should not be dumped.
+ * Actually this later behavior could apply to the Mirror Modifier as well, but the additional checks are
+ * costly and not necessary in the case of mirror, because each vertex is only merged to its own mirror.
+ *
+ * \note #BKE_mesh_recalc_tessellation has to run on the returned DM if you want to access tessfaces.
+ */
+Mesh *BKE_mesh_merge_verts(Mesh *mesh, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
+{
+ /* This was commented out back in 2013, see commit f45d8827bafe6b9eaf9de42f4054e9d84a21955d. */
+// #define USE_LOOPS
+
+ Mesh *result = NULL;
+
+ const int totvert = mesh->totvert;
+ const int totedge = mesh->totedge;
+ const int totloop = mesh->totloop;
+ const int totpoly = mesh->totpoly;
+
+ const int totvert_final = totvert - tot_vtargetmap;
+
+ MVert *mv, *mvert = MEM_malloc_arrayN(totvert_final, sizeof(*mvert), __func__);
+ int *oldv = MEM_malloc_arrayN(totvert_final, sizeof(*oldv), __func__);
+ int *newv = MEM_malloc_arrayN(totvert, sizeof(*newv), __func__);
+ STACK_DECLARE(mvert);
+ STACK_DECLARE(oldv);
+
+ /* Note: create (totedge + totloop) elements because partially invalid polys due to merge may require
+ * generating new edges, and while in 99% cases we'll still end with less final edges than totedge,
+ * cases can be forged that would end requiring more... */
+ MEdge *med, *medge = MEM_malloc_arrayN((totedge + totloop), sizeof(*medge), __func__);
+ int *olde = MEM_malloc_arrayN((totedge + totloop), sizeof(*olde), __func__);
+ int *newe = MEM_malloc_arrayN((totedge + totloop), sizeof(*newe), __func__);
+ STACK_DECLARE(medge);
+ STACK_DECLARE(olde);
+
+ MLoop *ml, *mloop = MEM_malloc_arrayN(totloop, sizeof(*mloop), __func__);
+ int *oldl = MEM_malloc_arrayN(totloop, sizeof(*oldl), __func__);
+#ifdef USE_LOOPS
+ int *newl = MEM_malloc_arrayN(totloop, sizeof(*newl), __func__);
+#endif
+ STACK_DECLARE(mloop);
+ STACK_DECLARE(oldl);
+
+ MPoly *mp, *mpoly = MEM_malloc_arrayN(totpoly, sizeof(*medge), __func__);
+ int *oldp = MEM_malloc_arrayN(totpoly, sizeof(*oldp), __func__);
+ STACK_DECLARE(mpoly);
+ STACK_DECLARE(oldp);
+
+ EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge);
+
+ int i, j, c;
+
+ PolyKey *poly_keys;
+ GSet *poly_gset = NULL;
+ MeshElemMap *poly_map = NULL;
+ int *poly_map_mem = NULL;
+
+ STACK_INIT(oldv, totvert_final);
+ STACK_INIT(olde, totedge);
+ STACK_INIT(oldl, totloop);
+ STACK_INIT(oldp, totpoly);
+
+ STACK_INIT(mvert, totvert_final);
+ STACK_INIT(medge, totedge);
+ STACK_INIT(mloop, totloop);
+ STACK_INIT(mpoly, totpoly);
+
+ /* fill newv with destination vertex indices */
+ mv = mesh->mvert;
+ c = 0;
+ for (i = 0; i < totvert; i++, mv++) {
+ if (vtargetmap[i] == -1) {
+ STACK_PUSH(oldv, i);
+ STACK_PUSH(mvert, *mv);
+ newv[i] = c++;
+ }
+ else {
+ /* dummy value */
+ newv[i] = 0;
+ }
+ }
+
+ /* now link target vertices to destination indices */
+ for (i = 0; i < totvert; i++) {
+ if (vtargetmap[i] != -1) {
+ newv[i] = newv[vtargetmap[i]];
+ }
+ }
+
+ /* Don't remap vertices in cddm->mloop, because we need to know the original
+ * indices in order to skip faces with all vertices merged.
+ * The "update loop indices..." section further down remaps vertices in mloop.
+ */
+
+ /* now go through and fix edges and faces */
+ med = mesh->medge;
+ c = 0;
+ for (i = 0; i < totedge; i++, med++) {
+ const unsigned int v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ const unsigned int v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ if (LIKELY(v1 != v2)) {
+ void **val_p;
+
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ newe[i] = POINTER_AS_INT(*val_p);
+ }
+ else {
+ STACK_PUSH(olde, i);
+ STACK_PUSH(medge, *med);
+ newe[i] = c;
+ *val_p = POINTER_FROM_INT(c);
+ c++;
+ }
+ }
+ else {
+ newe[i] = -1;
+ }
+ }
+
+ if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* In this mode, we need to determine, whenever a poly' vertices are all mapped */
+ /* if the targets already make up a poly, in which case the new poly is dropped */
+ /* This poly equality check is rather complex. We use a BLI_ghash to speed it up with a first level check */
+ PolyKey *mpgh;
+ poly_keys = MEM_malloc_arrayN(totpoly, sizeof(PolyKey), __func__);
+ poly_gset = BLI_gset_new_ex(poly_gset_hash_fn, poly_gset_compare_fn, __func__, totpoly);
+ /* Duplicates allowed because our compare function is not pure equality */
+ BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
+
+ mp = mesh->mpoly;
+ mpgh = poly_keys;
+ for (i = 0; i < totpoly; i++, mp++, mpgh++) {
+ mpgh->poly_index = i;
+ mpgh->totloops = mp->totloop;
+ ml = mesh->mloop + mp->loopstart;
+ mpgh->hash_sum = mpgh->hash_xor = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ mpgh->hash_sum += ml->v;
+ mpgh->hash_xor ^= ml->v;
+ }
+ BLI_gset_insert(poly_gset, mpgh);
+ }
+
+ /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */
+ /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */
+ BKE_mesh_vert_poly_map_create(
+ &poly_map, &poly_map_mem,
+ mesh->mpoly, mesh->mloop,
+ totvert, totpoly, totloop);
+ } /* done preparing for fast poly compare */
+
+
+ mp = mesh->mpoly;
+ mv = mesh->mvert;
+ for (i = 0; i < totpoly; i++, mp++) {
+ MPoly *mp_new;
+
+ ml = mesh->mloop + mp->loopstart;
+
+ /* check faces with all vertices merged */
+ bool all_vertices_merged = true;
+
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ if (vtargetmap[ml->v] == -1) {
+ all_vertices_merged = false;
+ /* This will be used to check for poly using several time the same vert. */
+ mv[ml->v].flag &= ~ME_VERT_TMP_TAG;
+ }
+ else {
+ /* This will be used to check for poly using several time the same vert. */
+ mv[vtargetmap[ml->v]].flag &= ~ME_VERT_TMP_TAG;
+ }
+ }
+
+ if (UNLIKELY(all_vertices_merged)) {
+ if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_MAPPED) {
+ /* In this mode, all vertices merged is enough to dump face */
+ continue;
+ }
+ else if (merge_mode == MESH_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* Additional condition for face dump: target vertices must make up an identical face */
+ /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
+ /* (2) second step is thorough but more costly poly compare */
+ int i_poly, v_target;
+ bool found = false;
+ PolyKey pkey;
+
+ /* Use poly_gset for fast (although not 100% certain) identification of same poly */
+ /* First, make up a poly_summary structure */
+ ml = mesh->mloop + mp->loopstart;
+ pkey.hash_sum = pkey.hash_xor = 0;
+ pkey.totloops = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
+ pkey.hash_sum += v_target;
+ pkey.hash_xor ^= v_target;
+ pkey.totloops++;
+ }
+ if (BLI_gset_haskey(poly_gset, &pkey)) {
+
+ /* There might be a poly that matches this one.
+ * We could just leave it there and say there is, and do a "continue".
+ * ... but we are checking whether there is an exact poly match.
+ * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
+ */
+
+ /* Consider current loop again */
+ ml = mesh->mloop + mp->loopstart;
+ /* Consider the target of the loop's first vert */
+ v_target = vtargetmap[ml->v];
+ /* Now see if v_target belongs to a poly that shares all vertices with source poly,
+ * in same order, or reverse order */
+
+ for (i_poly = 0; i_poly < poly_map[v_target].count; i_poly++) {
+ MPoly *target_poly = mesh->mpoly + *(poly_map[v_target].indices + i_poly);
+
+ if (cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, +1) ||
+ cddm_poly_compare(mesh->mloop, mp, target_poly, vtargetmap, -1))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ /* Current poly's vertices are mapped to a poly that is strictly identical */
+ /* Current poly is dumped */
+ continue;
+ }
+ }
+ }
+ }
+
+
+ /* Here either the poly's vertices were not all merged
+ * or they were all merged, but targets do not make up an identical poly,
+ * the poly is retained.
+ */
+ ml = mesh->mloop + mp->loopstart;
+
+ c = 0;
+ MLoop *last_valid_ml = NULL;
+ MLoop *first_valid_ml = NULL;
+ bool need_edge_from_last_valid_ml = false;
+ bool need_edge_to_first_valid_ml = false;
+ int created_edges = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ const uint mlv = (vtargetmap[ml->v] != -1) ? vtargetmap[ml->v] : ml->v;
+#ifndef NDEBUG
+ {
+ MLoop *next_ml = mesh->mloop + mp->loopstart + ((j + 1) % mp->totloop);
+ uint next_mlv = (vtargetmap[next_ml->v] != -1) ? vtargetmap[next_ml->v] : next_ml->v;
+ med = mesh->medge + ml->e;
+ uint v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ uint v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ BLI_assert((mlv == v1 && next_mlv == v2) || (mlv == v2 && next_mlv == v1));
+ }
+#endif
+ /* A loop is only valid if its matching edge is, and it's not reusing a vertex already used by this poly. */
+ if (LIKELY((newe[ml->e] != -1) && ((mv[mlv].flag & ME_VERT_TMP_TAG) == 0))) {
+ mv[mlv].flag |= ME_VERT_TMP_TAG;
+
+ if (UNLIKELY(last_valid_ml != NULL && need_edge_from_last_valid_ml)) {
+ /* We need to create a new edge between last valid loop and this one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
+ uint v2 = mlv;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = POINTER_AS_INT(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = POINTER_FROM_INT(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_from_last_valid_ml = false;
+ }
+
+#ifdef USE_LOOPS
+ newl[j + mp->loopstart] = STACK_SIZE(mloop);
+#endif
+ STACK_PUSH(oldl, j + mp->loopstart);
+ last_valid_ml = STACK_PUSH_RET_PTR(mloop);
+ *last_valid_ml = *ml;
+ if (first_valid_ml == NULL) {
+ first_valid_ml = last_valid_ml;
+ }
+ c++;
+
+ /* We absolutely HAVE to handle edge index remapping here, otherwise potential newly created edges
+ * in that part of code make remapping later totally unreliable. */
+ BLI_assert(newe[ml->e] != -1);
+ last_valid_ml->e = newe[ml->e];
+ }
+ else {
+ if (last_valid_ml != NULL) {
+ need_edge_from_last_valid_ml = true;
+ }
+ else {
+ need_edge_to_first_valid_ml = true;
+ }
+ }
+ }
+ if (UNLIKELY(last_valid_ml != NULL && !ELEM(first_valid_ml, NULL, last_valid_ml) &&
+ (need_edge_to_first_valid_ml || need_edge_from_last_valid_ml)))
+ {
+ /* We need to create a new edge between last valid loop and first valid one! */
+ void **val_p;
+
+ uint v1 = (vtargetmap[last_valid_ml->v] != -1) ? vtargetmap[last_valid_ml->v] : last_valid_ml->v;
+ uint v2 = (vtargetmap[first_valid_ml->v] != -1) ? vtargetmap[first_valid_ml->v] : first_valid_ml->v;
+ BLI_assert(v1 != v2);
+ if (BLI_edgehash_ensure_p(ehash, v1, v2, &val_p)) {
+ last_valid_ml->e = POINTER_AS_INT(*val_p);
+ }
+ else {
+ const int new_eidx = STACK_SIZE(medge);
+ STACK_PUSH(olde, olde[last_valid_ml->e]);
+ STACK_PUSH(medge, mesh->medge[last_valid_ml->e]);
+ medge[new_eidx].v1 = last_valid_ml->v;
+ medge[new_eidx].v2 = first_valid_ml->v;
+ /* DO NOT change newe mapping, could break actual values due to some deleted original edges. */
+ *val_p = POINTER_FROM_INT(new_eidx);
+ created_edges++;
+
+ last_valid_ml->e = new_eidx;
+ }
+ need_edge_to_first_valid_ml = need_edge_from_last_valid_ml = false;
+ }
+
+ if (UNLIKELY(c == 0)) {
+ BLI_assert(created_edges == 0);
+ continue;
+ }
+ else if (UNLIKELY(c < 3)) {
+ STACK_DISCARD(oldl, c);
+ STACK_DISCARD(mloop, c);
+ if (created_edges > 0) {
+ for (j = STACK_SIZE(medge) - created_edges; j < STACK_SIZE(medge); j++) {
+ BLI_edgehash_remove(ehash, medge[j].v1, medge[j].v2, NULL);
+ }
+ STACK_DISCARD(olde, created_edges);
+ STACK_DISCARD(medge, created_edges);
+ }
+ continue;
+ }
+
+ mp_new = STACK_PUSH_RET_PTR(mpoly);
+ *mp_new = *mp;
+ mp_new->totloop = c;
+ BLI_assert(mp_new->totloop >= 3);
+ mp_new->loopstart = STACK_SIZE(mloop) - c;
+
+ STACK_PUSH(oldp, i);
+ } /* end of the loop that tests polys */
+
+
+ if (poly_gset) {
+ // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset));
+
+ BLI_gset_free(poly_gset, NULL);
+ MEM_freeN(poly_keys);
+ }
+
+ /*create new cddm*/
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, STACK_SIZE(mvert), STACK_SIZE(medge), 0, STACK_SIZE(mloop), STACK_SIZE(mpoly));
+
+ /*update edge indices and copy customdata*/
+ med = medge;
+ for (i = 0; i < result->totedge; i++, med++) {
+ BLI_assert(newv[med->v1] != -1);
+ med->v1 = newv[med->v1];
+ BLI_assert(newv[med->v2] != -1);
+ med->v2 = newv[med->v2];
+
+ /* Can happen in case vtargetmap contains some double chains, we do not support that. */
+ BLI_assert(med->v1 != med->v2);
+
+ CustomData_copy_data(&mesh->edata, &result->edata, olde[i], i, 1);
+ }
+
+ /*update loop indices and copy customdata*/
+ ml = mloop;
+ for (i = 0; i < result->totloop; i++, ml++) {
+ /* Edge remapping has already be done in main loop handling part above. */
+ BLI_assert(newv[ml->v] != -1);
+ ml->v = newv[ml->v];
+
+ CustomData_copy_data(&mesh->ldata, &result->ldata, oldl[i], i, 1);
+ }
+
+ /*copy vertex customdata*/
+ mv = mvert;
+ for (i = 0; i < result->totvert; i++, mv++) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, oldv[i], i, 1);
+ }
+
+ /*copy poly customdata*/
+ mp = mpoly;
+ for (i = 0; i < result->totpoly; i++, mp++) {
+ CustomData_copy_data(&mesh->pdata, &result->pdata, oldp[i], i, 1);
+ }
+
+ /*copy over data. CustomData_add_layer can do this, need to look it up.*/
+ memcpy(result->mvert, mvert, sizeof(MVert) * STACK_SIZE(mvert));
+ memcpy(result->medge, medge, sizeof(MEdge) * STACK_SIZE(medge));
+ memcpy(result->mloop, mloop, sizeof(MLoop) * STACK_SIZE(mloop));
+ memcpy(result->mpoly, mpoly, sizeof(MPoly) * STACK_SIZE(mpoly));
+
+ MEM_freeN(mvert);
+ MEM_freeN(medge);
+ MEM_freeN(mloop);
+ MEM_freeN(mpoly);
+
+ MEM_freeN(newv);
+ MEM_freeN(newe);
+#ifdef USE_LOOPS
+ MEM_freeN(newl);
+#endif
+
+ MEM_freeN(oldv);
+ MEM_freeN(olde);
+ MEM_freeN(oldl);
+ MEM_freeN(oldp);
+
+ BLI_edgehash_free(ehash, NULL);
+
+ if (poly_map != NULL)
+ MEM_freeN(poly_map);
+ if (poly_map_mem != NULL)
+ MEM_freeN(poly_map_mem);
+
+ BKE_id_free(NULL, mesh);
+
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 62c81bf8cba..bdf5b3fddcc 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "BLI_utildefines.h"
@@ -41,10 +42,10 @@
#include "BKE_bvhutils.h"
#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h" /* own include */
+#include "BKE_mesh_runtime.h"
#include "BLI_strict_flags.h"
@@ -121,8 +122,8 @@ static bool mesh_remap_bvhtree_query_raycast(
* In other words, beyond a certain (relatively small) distance, all differences have more or less the same weight
* in final result, which allows to reduce influence of a few high differences, in favor of a global good matching.
*/
-float BKE_mesh_remap_calc_difference_from_dm(
- const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, DerivedMesh *dm_src)
+float BKE_mesh_remap_calc_difference_from_mesh(
+ const SpaceTransform *space_transform, const MVert *verts_dst, const int numverts_dst, Mesh *me_src)
{
BVHTreeFromMesh treedata = {NULL};
BVHTreeNearest nearest = {0};
@@ -131,7 +132,7 @@ float BKE_mesh_remap_calc_difference_from_dm(
float result = 0.0f;
int i;
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
@@ -250,8 +251,8 @@ static void mesh_calc_eigen_matrix(
/**
* Set r_space_transform so that best bbox of dst matches best bbox of src.
*/
-void BKE_mesh_remap_find_best_match_from_dm(
- const MVert *verts_dst, const int numverts_dst, DerivedMesh *dm_src, SpaceTransform *r_space_transform)
+void BKE_mesh_remap_find_best_match_from_mesh(
+ const MVert *verts_dst, const int numverts_dst, Mesh *me_src, SpaceTransform *r_space_transform)
{
/* Note that those are done so that we successively get actual mirror matrix (by multiplication of columns)... */
const float mirrors[][3] = {
@@ -269,15 +270,14 @@ void BKE_mesh_remap_find_best_match_from_dm(
float mat_src[4][4], mat_dst[4][4], best_mat_dst[4][4];
float best_match = FLT_MAX, match;
- const int numverts_src = dm_src->getNumVerts(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)numverts_src, __func__);
- dm_src->getVertCos(dm_src, vcos_src);
+ const int numverts_src = me_src->totvert;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
mesh_calc_eigen_matrix(NULL, (const float (*)[3])vcos_src, numverts_src, mat_src);
mesh_calc_eigen_matrix(verts_dst, NULL, numverts_dst, mat_dst);
BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
- match = BKE_mesh_remap_calc_difference_from_dm(r_space_transform, verts_dst, numverts_dst, dm_src);
+ match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src);
best_match = match;
copy_m4_m4(best_mat_dst, mat_dst);
@@ -288,7 +288,7 @@ void BKE_mesh_remap_find_best_match_from_dm(
mul_v3_fl(mat_dst[2], (*mirr)[2]);
BLI_space_transform_global_from_matrices(r_space_transform, mat_dst, mat_src);
- match = BKE_mesh_remap_calc_difference_from_dm(r_space_transform, verts_dst, numverts_dst, dm_src);
+ match = BKE_mesh_remap_calc_difference_from_mesh(r_space_transform, verts_dst, numverts_dst, me_src);
if (match < best_match) {
best_match = match;
copy_m4_m4(best_mat_dst, mat_dst);
@@ -430,9 +430,9 @@ typedef struct IslandResult {
/* Will be enough in 99% of cases. */
#define MREMAP_DEFAULT_BUFSIZE 32
-void BKE_mesh_remap_calc_verts_from_dm(
+void BKE_mesh_remap_calc_verts_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
- const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src,
+ const MVert *verts_dst, const int numverts_dst, const bool UNUSED(dirty_nors_dst), Mesh *me_src,
MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@@ -444,7 +444,7 @@ void BKE_mesh_remap_calc_verts_from_dm(
BKE_mesh_remap_init(r_map, numverts_dst);
if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numverts_dst == dm_src->getNumVerts(dm_src));
+ BLI_assert(numverts_dst == me_src->totvert);
for (i = 0; i < numverts_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -457,7 +457,7 @@ void BKE_mesh_remap_calc_verts_from_dm(
float tmp_co[3], tmp_no[3];
if (mode == MREMAP_MODE_VERT_NEAREST) {
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
@@ -478,11 +478,10 @@ void BKE_mesh_remap_calc_verts_from_dm(
}
}
else if (ELEM(mode, MREMAP_MODE_VERT_EDGE_NEAREST, MREMAP_MODE_VERT_EDGEINTERP_NEAREST)) {
- MEdge *edges_src = dm_src->getEdgeArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
- dm_src->getVertCos(dm_src, vcos_src);
+ MEdge *edges_src = me_src->medge;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
nearest.index = -1;
for (i = 0; i < numverts_dst; i++) {
@@ -530,18 +529,16 @@ void BKE_mesh_remap_calc_verts_from_dm(
else if (ELEM(mode, MREMAP_MODE_VERT_POLY_NEAREST, MREMAP_MODE_VERT_POLYINTERP_NEAREST,
MREMAP_MODE_VERT_POLYINTERP_VNORPROJ))
{
- MPoly *polys_src = dm_src->getPolyArray(dm_src);
- MLoop *loops_src = dm_src->getLoopArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
+ MPoly *polys_src = me_src->mpoly;
+ MLoop *loops_src = me_src->mloop;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
float (*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
int *indices = MEM_mallocN(sizeof(*indices) * tmp_buff_size, __func__);
float *weights = MEM_mallocN(sizeof(*weights) * tmp_buff_size, __func__);
- dm_src->getVertCos(dm_src, vcos_src);
-
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
for (i = 0; i < numverts_dst; i++) {
@@ -625,10 +622,10 @@ void BKE_mesh_remap_calc_verts_from_dm(
}
}
-void BKE_mesh_remap_calc_edges_from_dm(
+void BKE_mesh_remap_calc_edges_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
const MVert *verts_dst, const int numverts_dst, const MEdge *edges_dst, const int numedges_dst,
- const bool UNUSED(dirty_nors_dst), DerivedMesh *dm_src, MeshPairRemap *r_map)
+ const bool UNUSED(dirty_nors_dst), Mesh *me_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
@@ -639,7 +636,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
BKE_mesh_remap_init(r_map, numedges_dst);
if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numedges_dst == dm_src->getNumEdges(dm_src));
+ BLI_assert(numedges_dst == me_src->totedge);
for (i = 0; i < numedges_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -652,10 +649,10 @@ void BKE_mesh_remap_calc_edges_from_dm(
float tmp_co[3], tmp_no[3];
if (mode == MREMAP_MODE_EDGE_VERT_NEAREST) {
- const int num_verts_src = dm_src->getNumVerts(dm_src);
- const int num_edges_src = dm_src->getNumEdges(dm_src);
- MEdge *edges_src = dm_src->getEdgeArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
+ const int num_verts_src = me_src->totvert;
+ const int num_edges_src = me_src->totedge;
+ MEdge *edges_src = me_src->medge;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
MeshElemMap *vert_to_edge_src_map;
int *vert_to_edge_src_map_mem;
@@ -673,9 +670,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
&vert_to_edge_src_map, &vert_to_edge_src_map_mem,
edges_src, num_verts_src, num_edges_src);
- dm_src->getVertCos(dm_src, vcos_src);
-
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2);
nearest.index = -1;
for (i = 0; i < numedges_dst; i++) {
@@ -775,7 +770,7 @@ void BKE_mesh_remap_calc_edges_from_dm(
MEM_freeN(vert_to_edge_src_map_mem);
}
else if (mode == MREMAP_MODE_EDGE_NEAREST) {
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
nearest.index = -1;
for (i = 0; i < numedges_dst; i++) {
@@ -796,13 +791,12 @@ void BKE_mesh_remap_calc_edges_from_dm(
}
}
else if (mode == MREMAP_MODE_EDGE_POLY_NEAREST) {
- MEdge *edges_src = dm_src->getEdgeArray(dm_src);
- MPoly *polys_src = dm_src->getPolyArray(dm_src);
- MLoop *loops_src = dm_src->getLoopArray(dm_src);
- float (*vcos_src)[3] = MEM_mallocN(sizeof(*vcos_src) * (size_t)dm_src->getNumVerts(dm_src), __func__);
+ MEdge *edges_src = me_src->medge;
+ MPoly *polys_src = me_src->mpoly;
+ MLoop *loops_src = me_src->mloop;
+ float (*vcos_src)[3] = BKE_mesh_vertexCos_get(me_src, NULL);
- dm_src->getVertCos(dm_src, vcos_src);
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
for (i = 0; i < numedges_dst; i++) {
interp_v3_v3v3(tmp_co, verts_dst[edges_dst[i].v1].co, verts_dst[edges_dst[i].v2].co, 0.5f);
@@ -821,9 +815,9 @@ void BKE_mesh_remap_calc_edges_from_dm(
int best_eidx_src = -1;
for (; nloops--; ml_src++) {
- MEdge *me_src = &edges_src[ml_src->e];
- float *co1_src = vcos_src[me_src->v1];
- float *co2_src = vcos_src[me_src->v2];
+ MEdge *med_src = &edges_src[ml_src->e];
+ float *co1_src = vcos_src[med_src->v1];
+ float *co2_src = vcos_src[med_src->v2];
float co_src[3];
float dist_sq;
@@ -848,14 +842,14 @@ void BKE_mesh_remap_calc_edges_from_dm(
}
else if (mode == MREMAP_MODE_EDGE_EDGEINTERP_VNORPROJ) {
const int num_rays_min = 5, num_rays_max = 100;
- const int numedges_src = dm_src->getNumEdges(dm_src);
+ const int numedges_src = me_src->totedge;
/* Subtleness - this one we can allocate only max number of cast rays per edges! */
int *indices = MEM_mallocN(sizeof(*indices) * (size_t)min_ii(numedges_src, num_rays_max), __func__);
/* Here it's simpler to just allocate for all edges :/ */
float *weights = MEM_mallocN(sizeof(*weights) * (size_t)numedges_src, __func__);
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
for (i = 0; i < numedges_dst; i++) {
/* For each dst edge, we sample some rays from it (interpolated from its vertices)
@@ -1108,13 +1102,13 @@ static float mesh_remap_calc_loops_astar_f_cost(
#define ASTAR_STEPS_MAX 64
-void BKE_mesh_remap_calc_loops_from_dm(
+void BKE_mesh_remap_calc_loops_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
MVert *verts_dst, const int numverts_dst, MEdge *edges_dst, const int numedges_dst,
MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst,
CustomData *ldata_dst, CustomData *pdata_dst,
const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
- DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src,
+ Mesh *me_src,
MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@@ -1129,7 +1123,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (mode == MREMAP_MODE_TOPOLOGY) {
/* In topology mapping, we assume meshes are identical, islands included! */
- BLI_assert(numloops_dst == dm_src->getNumLoops(dm_src));
+ BLI_assert(numloops_dst == me_src->totloop);
for (i = 0; i < numloops_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -1172,19 +1166,15 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Unlike above, those are one-to-one mappings, simpler! */
int *loop_to_poly_map_src = NULL;
- bool verts_allocated_src;
- MVert *verts_src = DM_get_vert_array(dm_src, &verts_allocated_src);
- const int num_verts_src = dm_src->getNumVerts(dm_src);
+ MVert *verts_src = me_src->mvert;
+ const int num_verts_src = me_src->totvert;
float (*vcos_src)[3] = NULL;
- bool edges_allocated_src;
- MEdge *edges_src = DM_get_edge_array(dm_src, &edges_allocated_src);
- const int num_edges_src = dm_src->getNumEdges(dm_src);
- bool loops_allocated_src;
- MLoop *loops_src = DM_get_loop_array(dm_src, &loops_allocated_src);
- const int num_loops_src = dm_src->getNumLoops(dm_src);
- bool polys_allocated_src;
- MPoly *polys_src = DM_get_poly_array(dm_src, &polys_allocated_src);
- const int num_polys_src = dm_src->getNumPolys(dm_src);
+ MEdge *edges_src = me_src->medge;
+ const int num_edges_src = me_src->totedge;
+ MLoop *loops_src = me_src->mloop;
+ const int num_loops_src = me_src->totloop;
+ MPoly *polys_src = me_src->mpoly;
+ const int num_polys_src = me_src->totpoly;
const MLoopTri *looptri_src = NULL;
int num_looptri_src = 0;
@@ -1201,8 +1191,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
size_t islands_res_buff_size = MREMAP_DEFAULT_BUFSIZE;
if (!use_from_vert) {
- vcos_src = MEM_mallocN(sizeof(*vcos_src) * (size_t)num_verts_src, __func__);
- dm_src->getVertCos(dm_src, vcos_src);
+ vcos_src = BKE_mesh_vertexCos_get(me_src, NULL);
vcos_interp = MEM_mallocN(sizeof(*vcos_interp) * buff_size_interp, __func__);
indices_interp = MEM_mallocN(sizeof(*indices_interp) * buff_size_interp, __func__);
@@ -1218,11 +1207,12 @@ void BKE_mesh_remap_calc_loops_from_dm(
if (need_pnors_dst) {
/* Cache poly nors into a temp CDLayer. */
poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ const bool do_poly_nors_dst = (poly_nors_dst == NULL);
if (!poly_nors_dst) {
poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- if (dirty_nors_dst) {
+ if (dirty_nors_dst || do_poly_nors_dst) {
BKE_mesh_calc_normals_poly(
verts_dst, NULL, numverts_dst, loops_dst, polys_dst,
numloops_dst, numpolys_dst, poly_nors_dst, true);
@@ -1233,11 +1223,12 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* Cache poly nors into a temp CDLayer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
- if (dirty_nors_dst || !loop_nors_dst) {
- if (!loop_nors_dst) {
- loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
- CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
+ const bool do_loop_nors_dst = (loop_nors_dst == NULL);
+ if (!loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ if (dirty_nors_dst || do_loop_nors_dst) {
BKE_mesh_normals_loop_split(
verts_dst, numverts_dst, edges_dst, numedges_dst,
loops_dst, loop_nors_dst, numloops_dst,
@@ -1247,13 +1238,17 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
if (need_pnors_src || need_lnors_src) {
/* Simpler for now, calcNormals never stores pnors :( */
- dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
+ if (!CustomData_has_layer(&me_src->pdata, CD_NORMAL)) {
+ CustomData_add_layer(&me_src->pdata, CD_NORMAL, CD_CALLOC, NULL, me_src->totpoly);
+ CustomData_set_layer_flag(&me_src->pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ BKE_mesh_calc_normals_split(me_src);
if (need_pnors_src) {
- poly_nors_src = dm_src->getPolyDataArray(dm_src, CD_NORMAL);
+ poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL);
}
if (need_lnors_src) {
- loop_nors_src = dm_src->getLoopDataArray(dm_src, CD_NORMAL);
+ loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL);
}
}
}
@@ -1352,38 +1347,25 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
}
- /* verts 'ownership' is transfered to treedata here, which will handle its freeing. */
bvhtree_from_mesh_verts_ex(
- &treedata[tindex], verts_src, num_verts_src, verts_allocated_src,
+ &treedata[tindex], verts_src, num_verts_src, false,
verts_active, num_verts_active, 0.0, 2, 6);
- if (verts_allocated_src) {
- verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */
- }
}
MEM_freeN(verts_active);
}
else {
BLI_assert(num_trees == 1);
- bvhtree_from_mesh_get(&treedata[0], dm_src, BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_VERTS, 2);
}
}
else { /* We use polygons. */
if (use_islands) {
/* bvhtree here uses looptri faces... */
- const unsigned int dirty_tess_flag = dm_src->dirty & DM_DIRTY_TESS_CDLAYERS;
BLI_bitmap *looptri_active;
- /* We do not care about tessellated data here, only geometry itself is important. */
- if (dirty_tess_flag) {
- dm_src->dirty &= ~dirty_tess_flag;
- }
- if (dirty_tess_flag) {
- dm_src->dirty |= dirty_tess_flag;
- }
-
- looptri_src = dm_src->getLoopTriArray(dm_src);
- num_looptri_src = dm_src->getNumLoopTri(dm_src);
+ looptri_src = BKE_mesh_runtime_looptri_ensure(me_src);
+ num_looptri_src = me_src->runtime.looptris.len;
looptri_active = BLI_BITMAP_NEW((size_t)num_looptri_src, __func__);
for (tindex = 0; tindex < num_trees; tindex++) {
@@ -1396,26 +1378,19 @@ void BKE_mesh_remap_calc_loops_from_dm(
num_looptri_active++;
}
}
- /* verts and faces 'ownership' is transfered to treedata here, which will handle its freeing. */
bvhtree_from_mesh_looptri_ex(
&treedata[tindex],
- verts_src, verts_allocated_src,
- loops_src, loops_allocated_src,
+ verts_src, false,
+ loops_src, false,
looptri_src, num_looptri_src, false,
looptri_active, num_looptri_active, 0.0, 2, 6);
- if (verts_allocated_src) {
- verts_allocated_src = false; /* Only 'give' our verts once, to first tree! */
- }
- if (loops_allocated_src) {
- loops_allocated_src = false; /* Only 'give' our loops once, to first tree! */
- }
}
MEM_freeN(looptri_active);
}
else {
BLI_assert(num_trees == 1);
- bvhtree_from_mesh_get(&treedata[0], dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata[0], me_src, BVHTREE_FROM_LOOPTRI, 2);
}
}
@@ -1918,21 +1893,9 @@ void BKE_mesh_remap_calc_loops_from_dm(
BLI_astar_solution_free(&as_solution);
}
- if (verts_allocated_src) {
- MEM_freeN(verts_src);
- }
if (vcos_src) {
MEM_freeN(vcos_src);
}
- if (edges_allocated_src) {
- MEM_freeN(edges_src);
- }
- if (loops_allocated_src) {
- MEM_freeN(loops_src);
- }
- if (polys_allocated_src) {
- MEM_freeN(polys_src);
- }
if (vert_to_loop_map_src) {
MEM_freeN(vert_to_loop_map_src);
}
@@ -1975,11 +1938,11 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
-void BKE_mesh_remap_calc_polys_from_dm(
+void BKE_mesh_remap_calc_polys_from_mesh(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
MVert *verts_dst, const int numverts_dst, MLoop *loops_dst, const int numloops_dst,
MPoly *polys_dst, const int numpolys_dst, CustomData *pdata_dst, const bool dirty_nors_dst,
- DerivedMesh *dm_src, MeshPairRemap *r_map)
+ Mesh *me_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
@@ -2006,7 +1969,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
BKE_mesh_remap_init(r_map, numpolys_dst);
if (mode == MREMAP_MODE_TOPOLOGY) {
- BLI_assert(numpolys_dst == dm_src->getNumPolys(dm_src));
+ BLI_assert(numpolys_dst == me_src->totpoly);
for (i = 0; i < numpolys_dst; i++) {
mesh_remap_item_define(r_map, i, FLT_MAX, 0, 1, &i, &full_weight);
}
@@ -2017,7 +1980,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
BVHTreeRayHit rayhit = {0};
float hit_dist;
- bvhtree_from_mesh_get(&treedata, dm_src, BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_LOOPTRI, 2);
if (mode == MREMAP_MODE_POLY_NEAREST) {
nearest.index = -1;
@@ -2082,7 +2045,7 @@ void BKE_mesh_remap_calc_polys_from_dm(
*/
RNG *rng = BLI_rng_new(0);
- const size_t numpolys_src = (size_t)dm_src->getNumPolys(dm_src);
+ const size_t numpolys_src = (size_t)me_src->totpoly;
/* Here it's simpler to just allocate for all polys :/ */
int *indices = MEM_mallocN(sizeof(*indices) * numpolys_src, __func__);
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
new file mode 100644
index 00000000000..0931318f17a
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -0,0 +1,380 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_runtime.c
+ * \ingroup bke
+ */
+
+#include "atomic_ops.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_geom.h"
+#include "BLI_threads.h"
+
+#include "BKE_bvhutils.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_shrinkwrap.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Runtime Struct Utils
+ * \{ */
+
+static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+/**
+ * Default values defined at read time.
+ */
+void BKE_mesh_runtime_reset(Mesh *mesh)
+{
+ memset(&mesh->runtime, 0, sizeof(mesh->runtime));
+}
+
+void BKE_mesh_runtime_clear_cache(Mesh *mesh)
+{
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_mesh_batch_cache_free(mesh);
+ BKE_mesh_runtime_clear_edit_data(mesh);
+}
+
+/* This is a ported copy of DM_ensure_looptri_data(dm) */
+/**
+ * Ensure the array is large enough
+ *
+ * /note This function must always be thread-protected by caller. It should only be used by internal code.
+ */
+static void mesh_ensure_looptri_data(Mesh *mesh)
+{
+ const unsigned int totpoly = mesh->totpoly;
+ const int looptris_len = poly_to_tri_count(totpoly, mesh->totloop);
+
+ BLI_assert(mesh->runtime.looptris.array_wip == NULL);
+
+ SWAP(MLoopTri *, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+
+ if ((looptris_len > mesh->runtime.looptris.len_alloc) ||
+ (looptris_len < mesh->runtime.looptris.len_alloc * 2) ||
+ (totpoly == 0))
+ {
+ MEM_SAFE_FREE(mesh->runtime.looptris.array_wip);
+ mesh->runtime.looptris.len_alloc = 0;
+ mesh->runtime.looptris.len = 0;
+ }
+
+ if (totpoly) {
+ if (mesh->runtime.looptris.array_wip == NULL) {
+ mesh->runtime.looptris.array_wip = MEM_malloc_arrayN(looptris_len, sizeof(*mesh->runtime.looptris.array_wip), __func__);
+ mesh->runtime.looptris.len_alloc = looptris_len;
+ }
+
+ mesh->runtime.looptris.len = looptris_len;
+ }
+}
+
+/* This is a ported copy of CDDM_recalc_looptri(dm). */
+void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
+{
+ mesh_ensure_looptri_data(mesh);
+ BLI_assert(mesh->totpoly == 0 || mesh->runtime.looptris.array_wip != NULL);
+
+ BKE_mesh_recalc_looptri(
+ mesh->mloop, mesh->mpoly,
+ mesh->mvert,
+ mesh->totloop, mesh->totpoly,
+ mesh->runtime.looptris.array_wip);
+
+ BLI_assert(mesh->runtime.looptris.array == NULL);
+ atomic_cas_ptr((void **)&mesh->runtime.looptris.array, mesh->runtime.looptris.array, mesh->runtime.looptris.array_wip);
+ mesh->runtime.looptris.array_wip = NULL;
+}
+
+/* This is a ported copy of dm_getNumLoopTri(dm). */
+int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
+{
+ const int looptri_len = poly_to_tri_count(mesh->totpoly, mesh->totloop);
+ BLI_assert(ELEM(mesh->runtime.looptris.len, 0, looptri_len));
+ return looptri_len;
+}
+
+/* This is a ported copy of dm_getLoopTriArray(dm). */
+const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh)
+{
+ MLoopTri *looptri;
+
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_READ);
+ looptri = mesh->runtime.looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+
+ if (looptri != NULL) {
+ BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
+ }
+ else {
+ BLI_rw_mutex_lock(&loops_cache_lock, THREAD_LOCK_WRITE);
+ /* We need to ensure array is still NULL inside mutex-protected code, some other thread might have already
+ * recomputed those looptris. */
+ if (mesh->runtime.looptris.array == NULL) {
+ BKE_mesh_runtime_looptri_recalc(mesh);
+ }
+ looptri = mesh->runtime.looptris.array;
+ BLI_rw_mutex_unlock(&loops_cache_lock);
+ }
+ return looptri;
+}
+
+/* This is a copy of DM_verttri_from_looptri(). */
+void BKE_mesh_runtime_verttri_from_looptri(
+ MVertTri *r_verttri, const MLoop *mloop,
+ const MLoopTri *looptri, int looptri_num)
+{
+ int i;
+ for (i = 0; i < looptri_num; i++) {
+ r_verttri[i].tri[0] = mloop[looptri[i].tri[0]].v;
+ r_verttri[i].tri[1] = mloop[looptri[i].tri[1]].v;
+ r_verttri[i].tri[2] = mloop[looptri[i].tri[2]].v;
+ }
+}
+
+
+bool BKE_mesh_runtime_ensure_edit_data(struct Mesh *mesh)
+{
+ if (mesh->runtime.edit_data != NULL) {
+ return false;
+ }
+
+ mesh->runtime.edit_data = MEM_callocN(sizeof(EditMeshData), "EditMeshData");
+ return true;
+}
+
+bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
+{
+ if (mesh->runtime.edit_data == NULL) {
+ return false;
+ }
+
+ if (mesh->runtime.edit_data->polyCos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->polyCos);
+ if (mesh->runtime.edit_data->polyNos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->polyNos);
+ if (mesh->runtime.edit_data->vertexCos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->vertexCos);
+ if (mesh->runtime.edit_data->vertexNos != NULL)
+ MEM_freeN((void *)mesh->runtime.edit_data->vertexNos);
+
+ MEM_SAFE_FREE(mesh->runtime.edit_data);
+ return true;
+}
+
+void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
+{
+ bvhcache_free(&mesh->runtime.bvh_cache);
+ MEM_SAFE_FREE(mesh->runtime.looptris.array);
+ /* TODO(sergey): Does this really belong here? */
+ if (mesh->runtime.subdiv_ccg != NULL) {
+ BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg);
+ mesh->runtime.subdiv_ccg = NULL;
+ }
+ BKE_shrinkwrap_discard_boundary_data(mesh);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh Batch Cache Callbacks
+ * \{ */
+
+/* Draw Engine */
+void (*BKE_mesh_batch_cache_dirty_tag_cb)(Mesh *me, int mode) = NULL;
+void (*BKE_mesh_batch_cache_free_cb)(Mesh *me) = NULL;
+
+void BKE_mesh_batch_cache_dirty_tag(Mesh *me, int mode)
+{
+ if (me->runtime.batch_cache) {
+ BKE_mesh_batch_cache_dirty_tag_cb(me, mode);
+ }
+}
+void BKE_mesh_batch_cache_free(Mesh *me)
+{
+ if (me->runtime.batch_cache) {
+ BKE_mesh_batch_cache_free_cb(me);
+ }
+}
+
+/** \} */
+
+/** \name Mesh runtime debug helpers.
+ * \{ */
+/* evaluated mesh info printing function,
+ * to help track down differences output */
+
+#ifndef NDEBUG
+#include "BLI_dynstr.h"
+
+static void mesh_runtime_debug_info_layers(
+ DynStr *dynstr, CustomData *cd)
+{
+ int type;
+
+ for (type = 0; type < CD_NUMTYPES; type++) {
+ if (CustomData_has_layer(cd, type)) {
+ /* note: doesn't account for multiple layers */
+ const char *name = CustomData_layertype_name(type);
+ const int size = CustomData_sizeof(type);
+ const void *pt = CustomData_get_layer(cd, type);
+ const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(type, &structname, &structnum);
+ BLI_dynstr_appendf(
+ dynstr,
+ " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name, structname, type, (const void *)pt, size, pt_size);
+ }
+ }
+}
+
+char *BKE_mesh_runtime_debug_info(Mesh *me_eval)
+{
+ DynStr *dynstr = BLI_dynstr_new();
+ char *ret;
+
+ BLI_dynstr_appendf(dynstr, "{\n");
+ BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)me_eval);
+#if 0
+ const char *tstr;
+ switch (me_eval->type) {
+ case DM_TYPE_CDDM: tstr = "DM_TYPE_CDDM"; break;
+ case DM_TYPE_CCGDM: tstr = "DM_TYPE_CCGDM"; break;
+ default: tstr = "UNKNOWN"; break;
+ }
+ BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
+#endif
+ BLI_dynstr_appendf(dynstr, " 'totvert': %d,\n", me_eval->totvert);
+ BLI_dynstr_appendf(dynstr, " 'totedge': %d,\n", me_eval->totedge);
+ BLI_dynstr_appendf(dynstr, " 'totface': %d,\n", me_eval->totface);
+ BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me_eval->totpoly);
+ BLI_dynstr_appendf(dynstr, " 'deformed_only': %d,\n", me_eval->runtime.deformed_only);
+
+ BLI_dynstr_appendf(dynstr, " 'vertexLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->vdata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'edgeLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->edata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'loopLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->ldata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'polyLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->pdata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, " 'tessFaceLayers': (\n");
+ mesh_runtime_debug_info_layers(dynstr, &me_eval->fdata);
+ BLI_dynstr_appendf(dynstr, " ),\n");
+
+ BLI_dynstr_appendf(dynstr, "}\n");
+
+ ret = BLI_dynstr_get_cstring(dynstr);
+ BLI_dynstr_free(dynstr);
+ return ret;
+}
+
+void BKE_mesh_runtime_debug_print(Mesh *me_eval)
+{
+ char *str = BKE_mesh_runtime_debug_info(me_eval);
+ puts(str);
+ fflush(stdout);
+ MEM_freeN(str);
+}
+
+/* XXX Should go in customdata file? */
+void BKE_mesh_runtime_debug_print_cdlayers(CustomData *data)
+{
+ int i;
+ const CustomDataLayer *layer;
+
+ printf("{\n");
+
+ for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
+
+ const char *name = CustomData_layertype_name(layer->type);
+ const int size = CustomData_sizeof(layer->type);
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(layer->type, &structname, &structnum);
+ printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+ name, structname, layer->type, (const void *)layer->data, size, (int)(MEM_allocN_len(layer->data) / size));
+ }
+
+ printf("}\n");
+}
+
+bool BKE_mesh_runtime_is_valid(Mesh *me_eval)
+{
+ const bool do_verbose = true;
+ const bool do_fixes = false;
+
+ bool is_valid = true;
+ bool changed = true;
+
+ if (do_verbose) {
+ printf("MESH: %s\n", me_eval->id.name + 2);
+ }
+
+ is_valid &= BKE_mesh_validate_all_customdata(
+ &me_eval->vdata, &me_eval->edata, &me_eval->ldata, &me_eval->pdata,
+ false, /* setting mask here isn't useful, gives false positives */
+ do_verbose, do_fixes,
+ &changed);
+
+ is_valid &= BKE_mesh_validate_arrays(
+ me_eval,
+ me_eval->mvert, me_eval->totvert,
+ me_eval->medge, me_eval->totedge,
+ me_eval->mface, me_eval->totface,
+ me_eval->mloop, me_eval->totloop,
+ me_eval->mpoly, me_eval->totpoly,
+ me_eval->dvert,
+ do_verbose, do_fixes,
+ &changed);
+
+ BLI_assert(changed == false);
+
+ return is_valid;
+}
+
+#endif /* NDEBUG */
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
new file mode 100644
index 00000000000..b8d260e6922
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -0,0 +1,716 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/mesh_tangent.c
+ * \ingroup bke
+ *
+ * Functions to evaluate mesh tangents.
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_stack.h"
+#include "BLI_task.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_tangent.h"
+#include "BKE_report.h"
+
+#include "BLI_strict_flags.h"
+
+#include "atomic_ops.h"
+#include "mikktspace.h"
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Mesh Tangent Calculations (Single Layer)
+ * \{ */
+
+/* Tangent space utils. */
+
+/* User data. */
+typedef struct {
+ const MPoly *mpolys; /* faces */
+ const MLoop *mloops; /* faces's vertices */
+ const MVert *mverts; /* vertices */
+ const MLoopUV *luvs; /* texture coordinates */
+ float (*lnors)[3]; /* loops' normals */
+ float (*tangents)[4]; /* output tangents */
+ int num_polys; /* number of polygons */
+} BKEMeshToTangent;
+
+/* Mikktspace's API */
+static int get_num_faces(const SMikkTSpaceContext *pContext)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->num_polys;
+}
+
+static int get_num_verts_of_face(const SMikkTSpaceContext *pContext, const int face_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ return p_mesh->mpolys[face_idx].totloop;
+}
+
+static void get_position(const SMikkTSpaceContext *pContext, float r_co[3], const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ const int loop_idx = p_mesh->mpolys[face_idx].loopstart + vert_idx;
+ copy_v3_v3(r_co, p_mesh->mverts[p_mesh->mloops[loop_idx].v].co);
+}
+
+static void get_texture_coordinate(
+ const SMikkTSpaceContext *pContext, float r_uv[2], const int face_idx,
+ const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v2_v2(r_uv, p_mesh->luvs[p_mesh->mpolys[face_idx].loopstart + vert_idx].uv);
+}
+
+static void get_normal(const SMikkTSpaceContext *pContext, float r_no[3], const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ copy_v3_v3(r_no, p_mesh->lnors[p_mesh->mpolys[face_idx].loopstart + vert_idx]);
+}
+
+static void set_tspace(
+ const SMikkTSpaceContext *pContext, const float fv_tangent[3], const float face_sign,
+ const int face_idx, const int vert_idx)
+{
+ BKEMeshToTangent *p_mesh = (BKEMeshToTangent *)pContext->m_pUserData;
+ float *p_res = p_mesh->tangents[p_mesh->mpolys[face_idx].loopstart + vert_idx];
+ copy_v3_v3(p_res, fv_tangent);
+ p_res[3] = face_sign;
+}
+
+/**
+ * Compute simplified tangent space normals, i.e. tangent vector + sign of bi-tangent one, which combined with
+ * split normals can be used to recreate the full tangent space.
+ * Note: * The mesh should be made of only tris and quads!
+ */
+void BKE_mesh_calc_loop_tangent_single_ex(
+ const MVert *mverts, const int UNUSED(numVerts), const MLoop *mloops,
+ float (*r_looptangent)[4], float (*loopnors)[3], const MLoopUV *loopuvs,
+ const int UNUSED(numLoops), const MPoly *mpolys, const int numPolys,
+ ReportList *reports)
+{
+ BKEMeshToTangent mesh_to_tangent = {NULL};
+ SMikkTSpaceContext s_context = {NULL};
+ SMikkTSpaceInterface s_interface = {NULL};
+
+ const MPoly *mp;
+ int mp_index;
+
+ /* First check we do have a tris/quads only mesh. */
+ for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ if (mp->totloop > 4) {
+ BKE_report(reports, RPT_ERROR, "Tangent space can only be computed for tris/quads, aborting");
+ return;
+ }
+ }
+
+ /* Compute Mikktspace's tangent normals. */
+ mesh_to_tangent.mpolys = mpolys;
+ mesh_to_tangent.mloops = mloops;
+ mesh_to_tangent.mverts = mverts;
+ mesh_to_tangent.luvs = loopuvs;
+ mesh_to_tangent.lnors = loopnors;
+ mesh_to_tangent.tangents = r_looptangent;
+ mesh_to_tangent.num_polys = numPolys;
+
+ s_context.m_pUserData = &mesh_to_tangent;
+ s_context.m_pInterface = &s_interface;
+ s_interface.m_getNumFaces = get_num_faces;
+ s_interface.m_getNumVerticesOfFace = get_num_verts_of_face;
+ s_interface.m_getPosition = get_position;
+ s_interface.m_getTexCoord = get_texture_coordinate;
+ s_interface.m_getNormal = get_normal;
+ s_interface.m_setTSpaceBasic = set_tspace;
+
+ /* 0 if failed */
+ if (genTangSpaceDefault(&s_context) == false) {
+ BKE_report(reports, RPT_ERROR, "Mikktspace failed to generate tangents for this mesh!");
+ }
+}
+
+/**
+ * Wrapper around BKE_mesh_calc_loop_tangent_single_ex, which takes care of most boiling code.
+ * \note
+ * - There must be a valid loop's CD_NORMALS available.
+ * - The mesh should be made of only tris and quads!
+ */
+void BKE_mesh_calc_loop_tangent_single(Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], ReportList *reports)
+{
+ MLoopUV *loopuvs;
+ float (*loopnors)[3];
+
+ /* Check we have valid texture coordinates first! */
+ if (uvmap) {
+ loopuvs = CustomData_get_layer_named(&mesh->ldata, CD_MLOOPUV, uvmap);
+ }
+ else {
+ loopuvs = CustomData_get_layer(&mesh->ldata, CD_MLOOPUV);
+ }
+ if (!loopuvs) {
+ BKE_reportf(reports, RPT_ERROR, "Tangent space computation needs an UVMap, \"%s\" not found, aborting", uvmap);
+ return;
+ }
+
+ loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ if (!loopnors) {
+ BKE_report(reports, RPT_ERROR, "Tangent space computation needs loop normals, none found, aborting");
+ return;
+ }
+
+ BKE_mesh_calc_loop_tangent_single_ex(
+ mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
+ loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \name Mesh Tangent Calculations (All Layers)
+ * \{ */
+
+
+/* Necessary complexity to handle looptri's as quads for correct tangents */
+#define USE_LOOPTRI_DETECT_QUADS
+
+typedef struct {
+ const float (*precomputedFaceNormals)[3];
+ const float (*precomputedLoopNormals)[3];
+ const MLoopTri *looptri;
+ MLoopUV *mloopuv; /* texture coordinates */
+ const MPoly *mpoly; /* indices */
+ const MLoop *mloop; /* indices */
+ const MVert *mvert; /* vertices & normals */
+ const float (*orco)[3];
+ float (*tangent)[4]; /* destination */
+ int numTessFaces;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ /* map from 'fake' face index to looptri,
+ * quads will point to the first looptri of the quad */
+ const int *face_as_quad_map;
+ int num_face_as_quad_map;
+#endif
+
+} SGLSLMeshToTangent;
+
+/* interface */
+static int dm_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
+{
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ return pMesh->num_face_as_quad_map;
+#else
+ return pMesh->numTessFaces;
+#endif
+}
+
+static int dm_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
+{
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ if (pMesh->face_as_quad_map) {
+ const MLoopTri *lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ return 4;
+ }
+ }
+ return 3;
+#else
+ UNUSED_VARS(pContext, face_num);
+ return 3;
+#endif
+}
+
+static void dm_ts_GetPosition(
+ const SMikkTSpaceContext *pContext, float r_co[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+ const float *co;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ co = pMesh->mvert[pMesh->mloop[loop_index].v].co;
+ copy_v3_v3(r_co, co);
+}
+
+static void dm_ts_GetTextureCoordinate(
+ const SMikkTSpaceContext *pContext, float r_uv[2],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ if (pMesh->mloopuv != NULL) {
+ const float *uv = pMesh->mloopuv[loop_index].uv;
+ copy_v2_v2(r_uv, uv);
+ }
+ else {
+ const float *orco = pMesh->orco[pMesh->mloop[loop_index].v];
+ map_to_sphere(&r_uv[0], &r_uv[1], orco[0], orco[1], orco[2]);
+ }
+}
+
+static void dm_ts_GetNormal(
+ const SMikkTSpaceContext *pContext, float r_no[3],
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+finally:
+ if (pMesh->precomputedLoopNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedLoopNormals[loop_index]);
+ }
+ else if ((pMesh->mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
+ if (pMesh->precomputedFaceNormals) {
+ copy_v3_v3(r_no, pMesh->precomputedFaceNormals[lt->poly]);
+ }
+ else {
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ normal_quad_v3(
+ r_no,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 0].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 1].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 2].v].co,
+ pMesh->mvert[pMesh->mloop[mp->loopstart + 3].v].co);
+ }
+ else
+#endif
+ {
+ normal_tri_v3(
+ r_no,
+ pMesh->mvert[pMesh->mloop[lt->tri[0]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[1]].v].co,
+ pMesh->mvert[pMesh->mloop[lt->tri[2]].v].co);
+ }
+ }
+ }
+ else {
+ const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
+ normal_short_to_float_v3(r_no, no);
+ }
+}
+
+static void dm_ts_SetTSpace(
+ const SMikkTSpaceContext *pContext, const float fvTangent[3], const float fSign,
+ const int face_num, const int vert_index)
+{
+ //assert(vert_index >= 0 && vert_index < 4);
+ SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
+ const MLoopTri *lt;
+ uint loop_index;
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (pMesh->face_as_quad_map) {
+ lt = &pMesh->looptri[pMesh->face_as_quad_map[face_num]];
+ const MPoly *mp = &pMesh->mpoly[lt->poly];
+ if (mp->totloop == 4) {
+ loop_index = (uint)(mp->loopstart + vert_index);
+ goto finally;
+ }
+ /* fall through to regular triangle */
+ }
+ else {
+ lt = &pMesh->looptri[face_num];
+ }
+#else
+ lt = &pMesh->looptri[face_num];
+#endif
+ loop_index = lt->tri[vert_index];
+
+ float *pRes;
+
+finally:
+ pRes = pMesh->tangent[loop_index];
+ copy_v3_v3(pRes, fvTangent);
+ pRes[3] = fSign;
+}
+
+static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ struct SGLSLMeshToTangent *mesh2tangent = taskdata;
+ /* new computation method */
+ {
+ SMikkTSpaceContext sContext = {NULL};
+ SMikkTSpaceInterface sInterface = {NULL};
+
+ sContext.m_pUserData = mesh2tangent;
+ sContext.m_pInterface = &sInterface;
+ sInterface.m_getNumFaces = dm_ts_GetNumFaces;
+ sInterface.m_getNumVerticesOfFace = dm_ts_GetNumVertsOfFace;
+ sInterface.m_getPosition = dm_ts_GetPosition;
+ sInterface.m_getTexCoord = dm_ts_GetTextureCoordinate;
+ sInterface.m_getNormal = dm_ts_GetNormal;
+ sInterface.m_setTSpaceBasic = dm_ts_SetTSpace;
+
+ /* 0 if failed */
+ genTangSpaceDefault(&sContext);
+ }
+}
+
+void BKE_mesh_add_loop_tangent_named_layer_for_uv(
+ CustomData *uv_data, CustomData *tan_data, int numLoopData,
+ const char *layer_name)
+{
+ if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 &&
+ CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1)
+ {
+ CustomData_add_layer_named(
+ tan_data, CD_TANGENT, CD_CALLOC, NULL,
+ numLoopData, layer_name);
+ }
+}
+
+/**
+ * Here we get some useful information such as active uv layer name and search if it is already in tangent_names.
+ * Also, we calculate tangent_mask that works as a descriptor of tangents state.
+ * If tangent_mask has changed, then recalculate tangents.
+ */
+void BKE_mesh_calc_loop_tangent_step_0(
+ const CustomData *loopData, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_count,
+ bool *rcalc_act, bool *rcalc_ren, int *ract_uv_n, int *rren_uv_n,
+ char *ract_uv_name, char *rren_uv_name, short *rtangent_mask)
+{
+ /* Active uv in viewport */
+ int layer_index = CustomData_get_layer_index(loopData, CD_MLOOPUV);
+ *ract_uv_n = CustomData_get_active_layer(loopData, CD_MLOOPUV);
+ ract_uv_name[0] = 0;
+ if (*ract_uv_n != -1) {
+ strcpy(ract_uv_name, loopData->layers[*ract_uv_n + layer_index].name);
+ }
+
+ /* Active tangent in render */
+ *rren_uv_n = CustomData_get_render_layer(loopData, CD_MLOOPUV);
+ rren_uv_name[0] = 0;
+ if (*rren_uv_n != -1) {
+ strcpy(rren_uv_name, loopData->layers[*rren_uv_n + layer_index].name);
+ }
+
+ /* If active tangent not in tangent_names we take it into account */
+ *rcalc_act = false;
+ *rcalc_ren = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] == 0) {
+ calc_active_tangent = true;
+ }
+ }
+ if (calc_active_tangent) {
+ *rcalc_act = true;
+ *rcalc_ren = true;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (STREQ(ract_uv_name, tangent_names[i]))
+ *rcalc_act = false;
+ if (STREQ(rren_uv_name, tangent_names[i]))
+ *rcalc_ren = false;
+ }
+ }
+ *rtangent_mask = 0;
+
+ const int uv_layer_num = CustomData_number_of_layers(loopData, CD_MLOOPUV);
+ for (int n = 0; n < uv_layer_num; n++) {
+ const char *name = CustomData_get_layer_name(loopData, CD_MLOOPUV, n);
+ bool add = false;
+ for (int i = 0; i < tangent_names_count; i++) {
+ if (tangent_names[i][0] && STREQ(tangent_names[i], name)) {
+ add = true;
+ break;
+ }
+ }
+ if (!add && ((*rcalc_act && ract_uv_name[0] && STREQ(ract_uv_name, name)) ||
+ (*rcalc_ren && rren_uv_name[0] && STREQ(rren_uv_name, name))))
+ {
+ add = true;
+ }
+ if (add)
+ *rtangent_mask |= (short)(1 << n);
+ }
+
+ if (uv_layer_num == 0)
+ *rtangent_mask |= DM_TANGENT_MASK_ORCO;
+}
+
+/**
+ * See: #BKE_editmesh_loop_tangent_calc (matching logic).
+ */
+void BKE_mesh_calc_loop_tangent_ex(
+ const MVert *mvert,
+ const MPoly *mpoly, const uint mpoly_len,
+ const MLoop *mloop,
+ const MLoopTri *looptri,
+ const uint looptri_len,
+
+ CustomData *loopdata,
+ bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len,
+ const float (*poly_normals)[3],
+ const float (*loop_normals)[3],
+ const float (*vert_orco)[3],
+ /* result */
+ CustomData *loopdata_out,
+ const uint loopdata_out_len,
+ short *tangent_mask_curr_p)
+{
+ int act_uv_n = -1;
+ int ren_uv_n = -1;
+ bool calc_act = false;
+ bool calc_ren = false;
+ char act_uv_name[MAX_NAME];
+ char ren_uv_name[MAX_NAME];
+ short tangent_mask = 0;
+ short tangent_mask_curr = *tangent_mask_curr_p;
+
+ BKE_mesh_calc_loop_tangent_step_0(
+ loopdata, calc_active_tangent, tangent_names, tangent_names_len,
+ &calc_act, &calc_ren, &act_uv_n, &ren_uv_n, act_uv_name, ren_uv_name, &tangent_mask);
+ if ((tangent_mask_curr | tangent_mask) != tangent_mask_curr) {
+ /* Check we have all the needed layers */
+ /* Allocate needed tangent layers */
+ for (int i = 0; i < tangent_names_len; i++)
+ if (tangent_names[i][0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, tangent_names[i]);
+ if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1)
+ CustomData_add_layer_named(loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, "");
+ if (calc_act && act_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, act_uv_name);
+ if (calc_ren && ren_uv_name[0])
+ BKE_mesh_add_loop_tangent_named_layer_for_uv(loopdata, loopdata_out, (int)loopdata_out_len, ren_uv_name);
+
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ int num_face_as_quad_map;
+ int *face_as_quad_map = NULL;
+
+ /* map faces to quads */
+ if (looptri_len != mpoly_len) {
+ /* over alloc, since we dont know how many ngon or quads we have */
+
+ /* map fake face index to looptri */
+ face_as_quad_map = MEM_mallocN(sizeof(int) * looptri_len, __func__);
+ int k, j;
+ for (k = 0, j = 0; j < (int)looptri_len; k++, j++) {
+ face_as_quad_map[k] = j;
+ /* step over all quads */
+ if (mpoly[looptri[j].poly].totloop == 4) {
+ j++; /* skips the nest looptri */
+ }
+ }
+ num_face_as_quad_map = k;
+ }
+ else {
+ num_face_as_quad_map = (int)looptri_len;
+ }
+#endif
+
+ /* Calculation */
+ if (looptri_len != 0) {
+ TaskScheduler *scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ task_pool = BLI_task_pool_create(scheduler, NULL);
+
+ tangent_mask_curr = 0;
+ /* Calculate tangent layers */
+ SGLSLMeshToTangent data_array[MAX_MTFACE];
+ const int tangent_layer_num = CustomData_number_of_layers(loopdata_out, CD_TANGENT);
+ for (int n = 0; n < tangent_layer_num; n++) {
+ int index = CustomData_get_layer_index_n(loopdata_out, CD_TANGENT, n);
+ BLI_assert(n < MAX_MTFACE);
+ SGLSLMeshToTangent *mesh2tangent = &data_array[n];
+ mesh2tangent->numTessFaces = (int)looptri_len;
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ mesh2tangent->face_as_quad_map = face_as_quad_map;
+ mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
+#endif
+ mesh2tangent->mvert = mvert;
+ mesh2tangent->mpoly = mpoly;
+ mesh2tangent->mloop = mloop;
+ mesh2tangent->looptri = looptri;
+ /* Note, we assume we do have tessellated loop normals at this point (in case it is object-enabled),
+ * have to check this is valid...
+ */
+ mesh2tangent->precomputedLoopNormals = loop_normals;
+ mesh2tangent->precomputedFaceNormals = poly_normals;
+
+ mesh2tangent->orco = NULL;
+ mesh2tangent->mloopuv = CustomData_get_layer_named(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
+
+ /* Fill the resulting tangent_mask */
+ if (!mesh2tangent->mloopuv) {
+ mesh2tangent->orco = vert_orco;
+ if (!mesh2tangent->orco)
+ continue;
+
+ tangent_mask_curr |= DM_TANGENT_MASK_ORCO;
+ }
+ else {
+ int uv_ind = CustomData_get_named_layer_index(loopdata, CD_MLOOPUV, loopdata_out->layers[index].name);
+ int uv_start = CustomData_get_layer_index(loopdata, CD_MLOOPUV);
+ BLI_assert(uv_ind != -1 && uv_start != -1);
+ BLI_assert(uv_ind - uv_start < MAX_MTFACE);
+ tangent_mask_curr |= (short)(1 << (uv_ind - uv_start));
+ }
+
+ mesh2tangent->tangent = loopdata_out->layers[index].data;
+ BLI_task_pool_push(task_pool, DM_calc_loop_tangents_thread, mesh2tangent, false, TASK_PRIORITY_LOW);
+ }
+
+ BLI_assert(tangent_mask_curr == tangent_mask);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+ }
+ else {
+ tangent_mask_curr = tangent_mask;
+ }
+#ifdef USE_LOOPTRI_DETECT_QUADS
+ if (face_as_quad_map) {
+ MEM_freeN(face_as_quad_map);
+ }
+#undef USE_LOOPTRI_DETECT_QUADS
+
+#endif
+
+ *tangent_mask_curr_p = tangent_mask_curr;
+
+ /* Update active layer index */
+ int act_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, act_uv_n);
+ if (act_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[act_uv_index].name);
+ CustomData_set_layer_active_index(loopdata, CD_TANGENT, tan_index);
+ }/* else tangent has been built from orco */
+
+ /* Update render layer index */
+ int ren_uv_index = CustomData_get_layer_index_n(loopdata, CD_MLOOPUV, ren_uv_n);
+ if (ren_uv_index != -1) {
+ int tan_index = CustomData_get_named_layer_index(loopdata, CD_TANGENT, loopdata->layers[ren_uv_index].name);
+ CustomData_set_layer_render_index(loopdata, CD_TANGENT, tan_index);
+ }/* else tangent has been built from orco */
+ }
+}
+
+void BKE_mesh_calc_loop_tangents(
+ Mesh *me_eval, bool calc_active_tangent,
+ const char (*tangent_names)[MAX_NAME], int tangent_names_len)
+{
+ /* TODO(campbell): store in Mesh.runtime to avoid recalculation. */
+ short tangent_mask = 0;
+ BKE_mesh_calc_loop_tangent_ex(
+ me_eval->mvert,
+ me_eval->mpoly, (uint)me_eval->totpoly,
+ me_eval->mloop,
+ me_eval->runtime.looptris.array, (uint)me_eval->runtime.looptris.len,
+ &me_eval->ldata,
+ calc_active_tangent,
+ tangent_names, tangent_names_len,
+ CustomData_get_layer(&me_eval->pdata, CD_NORMAL),
+ CustomData_get_layer(&me_eval->ldata, CD_NORMAL),
+ CustomData_get_layer(&me_eval->vdata, CD_ORCO), /* may be NULL */
+ /* result */
+ &me_eval->ldata, (uint)me_eval->totloop,
+ &tangent_mask);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 82b3edb5b49..af4d1265cfd 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -43,10 +43,10 @@
#include "BLI_math_vector.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_mesh.h"
+#include "DEG_depsgraph.h"
+
#include "MEM_guardedalloc.h"
/* loop v/e are unsigned, so using max uint_32 value as invalid marker... */
@@ -618,62 +618,6 @@ bool BKE_mesh_validate_arrays(
}
/* Test same polys. */
-#if 0
- {
- bool p1_sub = true, p2_sub = true;
-
- /* NOTE: This performs a sub-set test. */
- /* XXX This (and the sort of verts list) is better than systematic
- * search of all verts of one list into the other if lists have
- * a fair amount of elements.
- * Not sure however it's worth it in this case?
- * But as we also need sorted vert list to check verts multi-used
- * (in first pass of checks)... */
- /* XXX If we consider only "equal" polys (i.e. using exactly same set of verts)
- * as invalid, better to replace this by a simple memory cmp... */
- while ((p1_nv && p2_nv) && (p1_sub || p2_sub)) {
- if (*p1_v < *p2_v) {
- if (p1_sub)
- p1_sub = false;
- p1_nv--;
- p1_v++;
- }
- else if (*p2_v < *p1_v) {
- if (p2_sub)
- p2_sub = false;
- p2_nv--;
- p2_v++;
- }
- else {
- /* Equality, both next verts. */
- p1_nv--;
- p2_nv--;
- p1_v++;
- p2_v++;
- }
- }
- if (p1_nv && p1_sub)
- p1_sub = false;
- else if (p2_nv && p2_sub)
- p2_sub = false;
-
- if (p1_sub && p2_sub) {
- PRINT("\tPolys %u and %u use same vertices, considering poly %u as invalid.\n",
- prev_sp->index, sp->index, sp->index);
- sp->invalid = true;
- }
- /* XXX In fact, these might be valid? :/ */
- else if (p1_sub) {
- PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", sp->index, prev_sp->index);
- sp->invalid = true;
- }
- else if (p2_sub) {
- PRINT("\t%u is a sub-poly of %u, considering it as invalid.\n", prev_sp->index, sp->index);
- prev_sp->invalid = true;
- prev_sp = sp; /* sp is new reference poly. */
- }
- }
-#else
if ((p1_nv == p2_nv) && (memcmp(p1_v, p2_v, p1_nv * sizeof(*p1_v)) == 0)) {
if (do_verbose) {
PRINT_ERR("\tPolys %u and %u use same vertices (%d",
@@ -687,7 +631,6 @@ bool BKE_mesh_validate_arrays(
}
sp->invalid = true;
}
-#endif
else {
prev_sp = sp;
}
@@ -939,7 +882,7 @@ bool BKE_mesh_validate_all_customdata(
{
bool is_valid = true;
bool is_change_v, is_change_e, is_change_l, is_change_p;
- int tot_texpoly, tot_uvloop, tot_vcolloop;
+ int tot_uvloop, tot_vcolloop;
CustomDataMask mask = check_meshmask ? CD_MASK_MESH : 0;
is_valid &= mesh_validate_customdata(vdata, mask, do_verbose, do_fixes, &is_change_v);
@@ -947,17 +890,8 @@ bool BKE_mesh_validate_all_customdata(
is_valid &= mesh_validate_customdata(ldata, mask, do_verbose, do_fixes, &is_change_l);
is_valid &= mesh_validate_customdata(pdata, mask, do_verbose, do_fixes, &is_change_p);
- tot_texpoly = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
tot_uvloop = CustomData_number_of_layers(ldata, CD_MLOOPUV);
tot_vcolloop = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
- if (tot_texpoly != tot_uvloop) {
- PRINT_ERR("\tCustomDataLayer mismatch, tot_texpoly(%d), tot_uvloop(%d)\n",
- tot_texpoly, tot_uvloop);
- }
- if (tot_texpoly > MAX_MTFACE) {
- PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, tot_texpoly - MAX_MTFACE);
- }
if (tot_uvloop > MAX_MTFACE) {
PRINT_ERR("\tMore UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
MAX_MTFACE, tot_uvloop - MAX_MTFACE);
@@ -968,18 +902,10 @@ bool BKE_mesh_validate_all_customdata(
}
/* check indices of clone/stencil */
- if (do_fixes && CustomData_get_clone_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) {
- CustomData_set_layer_clone(pdata, CD_MTEXPOLY, 0);
- is_change_p = true;
- }
if (do_fixes && CustomData_get_clone_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
CustomData_set_layer_clone(ldata, CD_MLOOPUV, 0);
is_change_l = true;
}
- if (do_fixes && CustomData_get_stencil_layer(pdata, CD_MTEXPOLY) >= tot_texpoly) {
- CustomData_set_layer_stencil(pdata, CD_MTEXPOLY, 0);
- is_change_p = true;
- }
if (do_fixes && CustomData_get_stencil_layer(ldata, CD_MLOOPUV) >= tot_uvloop) {
CustomData_set_layer_stencil(ldata, CD_MLOOPUV, 0);
is_change_l = true;
@@ -991,7 +917,7 @@ bool BKE_mesh_validate_all_customdata(
}
/**
- * \see #DM_is_valid to call on derived meshes
+ * Validates and corrects a Mesh.
*
* \returns true if a change is made.
*/
@@ -1022,7 +948,7 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_
&changed);
if (changed) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
return true;
}
else {
@@ -1031,61 +957,39 @@ bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_
}
/**
- * Duplicate of BM_mesh_cd_validate() for Mesh data.
+ * Checks if a Mesh is valid without any modification. This is always verbose.
+ *
+ * \see #DM_is_valid to call on derived meshes
+ *
+ * \returns is_valid.
*/
-void BKE_mesh_cd_validate(Mesh *me)
+bool BKE_mesh_is_valid(Mesh *me)
{
- int totlayer_mtex = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
- int totlayer_uv = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
- int totlayer_mcol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
- int mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
- int uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
- int i;
+ const bool do_verbose = true;
+ const bool do_fixes = false;
- /* XXX For now, do not delete those, just warn they are not really usable. */
- if (UNLIKELY(totlayer_mtex > MAX_MTFACE)) {
- printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, totlayer_mtex - MAX_MTFACE);
- }
- if (UNLIKELY(totlayer_uv > MAX_MTFACE)) {
- printf("WARNING! More UV layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MTFACE, totlayer_uv - MAX_MTFACE);
- }
- if (UNLIKELY(totlayer_mcol > MAX_MCOL)) {
- printf("WARNING! More VCol layers than %d allowed, %d last ones won't be available for render, shaders, etc.\n",
- MAX_MCOL, totlayer_mcol - MAX_MCOL);
- }
+ bool is_valid = true;
+ bool changed = true;
- if (LIKELY(totlayer_mtex == totlayer_uv)) {
- /* pass */
- }
- else if (totlayer_mtex < totlayer_uv) {
- do {
- const char *from_name = me->ldata.layers[uv_index + totlayer_mtex].name;
- CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, from_name);
- CustomData_set_layer_unique_name(&me->pdata, totlayer_mtex);
- } while (totlayer_uv != ++totlayer_mtex);
- mtex_index = CustomData_get_layer_index(&me->pdata, CD_MTEXPOLY);
- }
- else if (totlayer_uv < totlayer_mtex) {
- do {
- const char *from_name = me->pdata.layers[mtex_index + totlayer_uv].name;
- CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, from_name);
- CustomData_set_layer_unique_name(&me->ldata, totlayer_uv);
- } while (totlayer_mtex != ++totlayer_uv);
- uv_index = CustomData_get_layer_index(&me->ldata, CD_MLOOPUV);
- }
+ is_valid &= BKE_mesh_validate_all_customdata(
+ &me->vdata, &me->edata, &me->ldata, &me->pdata,
+ false, /* setting mask here isn't useful, gives false positives */
+ do_verbose, do_fixes, &changed);
- BLI_assert(totlayer_mtex == totlayer_uv);
+ is_valid &= BKE_mesh_validate_arrays(
+ me,
+ me->mvert, me->totvert,
+ me->medge, me->totedge,
+ me->mface, me->totface,
+ me->mloop, me->totloop,
+ me->mpoly, me->totpoly,
+ me->dvert,
+ do_verbose, do_fixes,
+ &changed);
- /* Check uv/tex names match as well!!! */
- for (i = 0; i < totlayer_mtex; i++, mtex_index++, uv_index++) {
- const char *name_src = me->pdata.layers[mtex_index].name;
- const char *name_dst = me->ldata.layers[uv_index].name;
- if (!STREQ(name_src, name_dst)) {
- BKE_mesh_uv_cdlayer_rename_index(me, mtex_index, uv_index, -1, name_src, false);
- }
- }
+ BLI_assert(changed == false);
+
+ return is_valid;
}
/**
@@ -1108,7 +1012,7 @@ bool BKE_mesh_validate_material_indices(Mesh *me)
}
if (!is_valid) {
- DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ DEG_id_tag_update(&me->id, OB_RECALC_DATA);
return true;
}
else {
@@ -1540,4 +1444,78 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool update, const bool select)
BLI_edgehash_free(eh, NULL);
}
+
+void BKE_mesh_calc_edges_loose(Mesh *mesh)
+{
+ MEdge *med = mesh->medge;
+ for (int i = 0; i < mesh->totedge; i++, med++) {
+ med->flag |= ME_LOOSEEDGE;
+ }
+ MLoop *ml = mesh->mloop;
+ for (int i = 0; i < mesh->totloop; i++, ml++) {
+ mesh->medge[ml->e].flag &= ~ME_LOOSEEDGE;
+ }
+}
+
+/**
+ * Calculate/create edges from tessface data
+ *
+ * \param mesh The mesh to add edges into
+ */
+
+void BKE_mesh_calc_edges_tessface(Mesh *mesh)
+{
+ CustomData edgeData;
+ EdgeSetIterator *ehi;
+ MFace *mf = mesh->mface;
+ MEdge *med;
+ EdgeSet *eh;
+ int i, *index, numEdges, numFaces = mesh->totface;
+
+ eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces));
+
+ for (i = 0; i < numFaces; i++, mf++) {
+ BLI_edgeset_add(eh, mf->v1, mf->v2);
+ BLI_edgeset_add(eh, mf->v2, mf->v3);
+
+ if (mf->v4) {
+ BLI_edgeset_add(eh, mf->v3, mf->v4);
+ BLI_edgeset_add(eh, mf->v4, mf->v1);
+ }
+ else {
+ BLI_edgeset_add(eh, mf->v3, mf->v1);
+ }
+ }
+
+ numEdges = BLI_edgeset_len(eh);
+
+ /* write new edges into a temporary CustomData */
+ CustomData_reset(&edgeData);
+ CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+
+ med = CustomData_get_layer(&edgeData, CD_MEDGE);
+ index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
+
+ for (ehi = BLI_edgesetIterator_new(eh), i = 0;
+ BLI_edgesetIterator_isDone(ehi) == false;
+ BLI_edgesetIterator_step(ehi), i++, med++, index++)
+ {
+ BLI_edgesetIterator_getKey(ehi, &med->v1, &med->v2);
+
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ *index = ORIGINDEX_NONE;
+ }
+ BLI_edgesetIterator_free(ehi);
+
+ /* free old CustomData and assign new one */
+ CustomData_free(&mesh->edata, mesh->totedge);
+ mesh->edata = edgeData;
+ mesh->totedge = numEdges;
+
+ mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
+
+ BLI_edgeset_free(eh);
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 723b4a5aa97..73a9d462687 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -46,6 +46,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_utildefines.h"
@@ -58,17 +59,25 @@
#include "BLT_translation.h"
#include "BKE_appdir.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
+#include "BKE_idcode.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_mesh.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_DerivedMesh.h"
/* may move these, only for modifier_path_relbase */
#include "BKE_main.h"
/* end */
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "MOD_modifiertypes.h"
static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL};
@@ -127,6 +136,7 @@ ModifierData *modifier_new(int type)
md->type = type;
md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded;
+ md->flag = eModifierFlag_StaticOverride_Local;
if (mti->flags & eModifierTypeFlag_EnableInEditmode)
md->mode |= eModifierMode_Editmode;
@@ -283,7 +293,7 @@ void modifiers_foreachTexLink(Object *ob, TexWalkFunc walk, void *userData)
/* callback's can use this
* to avoid copying every member.
*/
-void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst)
+void modifier_copyData_generic(const ModifierData *md_src, ModifierData *md_dst, const int UNUSED(flag))
{
const ModifierTypeInfo *mti = modifierType_getInfo(md_src->type);
@@ -313,9 +323,10 @@ void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
target->mode = md->mode;
+ target->flag = md->flag;
if (mti->copyData) {
- mti->copyData(md, target);
+ mti->copyData(md, target, flag);
}
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
@@ -338,9 +349,7 @@ bool modifier_supportsCage(struct Scene *scene, ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
- return ((!mti->isDisabled || !mti->isDisabled(md, 0)) &&
+ return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
(mti->flags & eModifierTypeFlag_SupportsEditmode) &&
modifier_supportsMapping(md));
}
@@ -349,11 +358,9 @@ bool modifier_couldBeCage(struct Scene *scene, ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
return ((md->mode & eModifierMode_Realtime) &&
(md->mode & eModifierMode_Editmode) &&
- (!mti->isDisabled || !mti->isDisabled(md, 0)) &&
+ (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) &&
modifier_supportsMapping(md));
}
@@ -410,9 +417,7 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
bool supports_mapping;
- md->scene = scene;
-
- if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
+ if (mti->isDisabled && mti->isDisabled(scene, md, 0)) continue;
if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
if (md->mode & eModifierMode_DisableTemporary) continue;
@@ -468,14 +473,12 @@ bool modifiers_isParticleEnabled(Object *ob)
*
* \param scene Current scene, may be NULL, in which case isDisabled callback of the modifier is never called.
*/
-bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode)
+bool modifier_isEnabled(const struct Scene *scene, ModifierData *md, int required_mode)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- md->scene = scene;
-
if ((md->mode & required_mode) != required_mode) return false;
- if (scene != NULL && mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false;
+ if (scene != NULL && mti->isDisabled && mti->isDisabled(scene, md, required_mode == eModifierMode_Render)) return false;
if (md->mode & eModifierMode_DisableTemporary) return false;
if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false;
@@ -619,6 +622,27 @@ Object *modifiers_isDeformedByArmature(Object *ob)
return NULL;
}
+Object *modifiers_isDeformedByMeshDeform(Object *ob)
+{
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ MeshDeformModifierData *mdmd = NULL;
+
+ /* return the first selected armature, this lets us use multiple armatures */
+ for (; md; md = md->next) {
+ if (md->type == eModifierType_MeshDeform) {
+ mdmd = (MeshDeformModifierData *) md;
+ if (mdmd->object && (mdmd->object->flag & SELECT))
+ return mdmd->object;
+ }
+ }
+
+ if (mdmd) /* if were still here then return the last armature */
+ return mdmd->object;
+
+ return NULL;
+}
+
/* Takes an object and returns its first selected lattice, else just its lattice
* This should work for multiple lattices per object
*/
@@ -686,7 +710,7 @@ bool modifiers_usesArmature(Object *ob, bArmature *arm)
bool modifier_isCorrectableDeformed(ModifierData *md)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- return (mti->deformMatricesEM != NULL);
+ return mti->deformMatricesEM != NULL;
}
bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
@@ -695,9 +719,9 @@ bool modifiers_isCorrectableDeformed(struct Scene *scene, Object *ob)
ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
int required_mode = eModifierMode_Realtime;
- if (ob->mode == OB_MODE_EDIT)
+ if (ob->mode == OB_MODE_EDIT) {
required_mode |= eModifierMode_Editmode;
-
+ }
for (; md; md = md->next) {
if (!modifier_isEnabled(scene, md, required_mode)) {
/* pass */
@@ -802,61 +826,104 @@ void modifier_path_init(char *path, int path_maxlen, const char *name)
/* wrapper around ModifierTypeInfo.applyModifier that ensures valid normals */
-struct DerivedMesh *modwrap_applyModifier(
- ModifierData *md, Object *ob,
- struct DerivedMesh *dm,
- ModifierApplyFlag flag)
+struct Mesh *modwrap_applyModifier(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct Mesh *me)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
+ BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- DM_ensure_normals(dm);
+ BKE_mesh_calc_normals(me);
}
- return mti->applyModifier(md, ob, dm, flag);
+ return mti->applyModifier(md, ctx, me);
}
-struct DerivedMesh *modwrap_applyModifierEM(
- ModifierData *md, Object *ob,
- struct BMEditMesh *em,
- DerivedMesh *dm,
- ModifierApplyFlag flag)
+void modwrap_deformVerts(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ Mesh *me, float (*vertexCos)[3], int numVerts)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
+ BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
- if (mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- DM_ensure_normals(dm);
+ if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ BKE_mesh_calc_normals(me);
}
- return mti->applyModifierEM(md, ob, em, dm, flag);
+ mti->deformVerts(md, ctx, me, vertexCos, numVerts);
}
-void modwrap_deformVerts(
- ModifierData *md, Object *ob,
- DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts,
- ModifierApplyFlag flag)
+void modwrap_deformVertsEM(
+ ModifierData *md, const ModifierEvalContext *ctx,
+ struct BMEditMesh *em, Mesh *me,
+ float (*vertexCos)[3], int numVerts)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
+ BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
- if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- DM_ensure_normals(dm);
+ if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+ BKE_mesh_calc_normals(me);
}
- mti->deformVerts(md, ob, dm, vertexCos, numVerts, flag);
+ mti->deformVertsEM(md, ctx, em, me, vertexCos, numVerts);
}
-void modwrap_deformVertsEM(
- ModifierData *md, Object *ob,
- struct BMEditMesh *em, DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts)
+/* end modifier callback wrappers */
+
+
+/* wrappers for modifier callbacks that accept Mesh and select the proper implementation
+ * depending on if the modifier has been ported to Mesh or is still using DerivedMesh
+ */
+
+/* deprecated variants of above that accept DerivedMesh */
+
+struct DerivedMesh *modifier_applyModifier_DM_deprecated(
+ struct ModifierData *md, const ModifierEvalContext *ctx,
+ struct DerivedMesh *dm)
{
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- BLI_assert(!dm || CustomData_has_layer(&dm->polyData, CD_NORMAL) == false);
- if (dm && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
- DM_ensure_normals(dm);
+ /* TODO(sybren): deduplicate all the copies of this code in this file. */
+ Mesh *mesh = NULL;
+ if (dm != NULL) {
+ mesh = BKE_id_new_nomain(ID_ME, NULL);
+ DM_to_mesh(dm, mesh, ctx->object, CD_MASK_EVERYTHING, false);
}
- mti->deformVertsEM(md, ob, em, dm, vertexCos, numVerts);
+
+ struct Mesh *new_mesh = mti->applyModifier(md, ctx, mesh);
+
+ /* Make a DM that doesn't reference new_mesh so we can free the latter. */
+ DerivedMesh *ndm = CDDM_from_mesh_ex(new_mesh, CD_DUPLICATE, CD_MASK_EVERYTHING);
+
+ if (new_mesh != mesh) {
+ BKE_id_free(NULL, new_mesh);
+ }
+ if (mesh != NULL) {
+ BKE_id_free(NULL, mesh);
+ }
+
+ return ndm;
+
+}
+
+/**
+ * Get evaluated mesh for other evaluated object, which is used as an operand for the modifier,
+ * e.g. second operand for boolean modifier.
+ * Note thqt modifiers in stack always get fully evaluated COW ID pointers, never original ones. Makes things simpler.
+ */
+Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval, bool *r_free_mesh)
+{
+ Mesh *me;
+
+ if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) {
+ /* Note: currently we have no equivalent to derived cagemesh or even final dm in BMEditMesh...
+ * This is TODO in core depsgraph/modifier stack code still. */
+ BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, 0);
+ *r_free_mesh = true;
+ }
+ else {
+ me = ob_eval->runtime.mesh_eval;
+ *r_free_mesh = false;
+ }
+
+ return me;
}
-/* end modifier callback wrappers */
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
deleted file mode 100644
index 4de876f1060..00000000000
--- a/source/blender/blenkernel/intern/modifiers_bmesh.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 by the Blender Foundation.
- * All rights reserved.
- *
- * Contributor(s): Joseph Eagar
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- */
-
-/** \file blender/blenkernel/intern/modifiers_bmesh.c
- * \ingroup bke
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_alloca.h"
-
-#include "BKE_DerivedMesh.h"
-#include "BKE_editmesh.h"
-
-/* Static function for alloc */
-static BMFace *bm_face_create_from_mpoly(
- MPoly *mp, MLoop *ml,
- BMesh *bm, BMVert **vtable, BMEdge **etable)
-{
- BMVert **verts = BLI_array_alloca(verts, mp->totloop);
- BMEdge **edges = BLI_array_alloca(edges, mp->totloop);
- int j;
-
- for (j = 0; j < mp->totloop; j++, ml++) {
- verts[j] = vtable[ml->v];
- edges[j] = etable[ml->e];
- }
-
- return BM_face_create(bm, verts, edges, mp->totloop, NULL, BM_CREATE_SKIP_CD);
-}
-
-/**
- * The main function for copying DerivedMesh data into BMesh.
- *
- * \note The mesh may already have geometry. see 'is_init'
- */
-void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
-{
- MVert *mv, *mvert;
- MEdge *me, *medge;
- MPoly *mpoly, *mp;
- MLoop *mloop;
- BMVert *v, **vtable;
- BMEdge *e, **etable;
- float (*face_normals)[3];
- BMFace *f;
- int i, j, totvert, totedge /* , totface */ /* UNUSED */ ;
- bool is_init = (bm->totvert == 0) && (bm->totedge == 0) && (bm->totface == 0);
- char has_orig_htype = 0;
-
- int cd_vert_bweight_offset;
- int cd_edge_bweight_offset;
- int cd_edge_crease_offset;
-
- if (is_init == false) {
- /* check if we have an origflag */
- has_orig_htype |= CustomData_has_layer(&bm->vdata, CD_ORIGINDEX) ? BM_VERT : 0;
- has_orig_htype |= CustomData_has_layer(&bm->edata, CD_ORIGINDEX) ? BM_EDGE : 0;
- has_orig_htype |= CustomData_has_layer(&bm->pdata, CD_ORIGINDEX) ? BM_FACE : 0;
- }
-
- /*merge custom data layout*/
- CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT);
- CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_EDGE);
- CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_LOOP);
- CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_FACE);
-
- if (is_init) {
- BM_mesh_cd_flag_apply(bm, dm->cd_flag);
- }
-
- cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
- cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
- cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
-
- totvert = dm->getNumVerts(dm);
- totedge = dm->getNumEdges(dm);
- /* totface = dm->getNumPolys(dm); */ /* UNUSED */
-
- vtable = MEM_mallocN(sizeof(*vtable) * totvert, __func__);
- etable = MEM_mallocN(sizeof(*etable) * totedge, __func__);
-
- /*do verts*/
- bool vert_allocated;
- mv = mvert = DM_get_vert_array(dm, &vert_allocated);
- for (i = 0; i < totvert; i++, mv++) {
- v = BM_vert_create(bm, mv->co, NULL, BM_CREATE_SKIP_CD);
- normal_short_to_float_v3(v->no, mv->no);
- v->head.hflag = BM_vert_flag_from_mflag(mv->flag);
- BM_elem_index_set(v, i); /* set_inline */
-
- CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data, true);
- vtable[i] = v;
-
- /* add bevel weight */
- if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mv->bweight / 255.0f);
-
- if (UNLIKELY(has_orig_htype & BM_VERT)) {
- int *orig_index = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_ORIGINDEX);
- *orig_index = ORIGINDEX_NONE;
- }
- }
- if (vert_allocated) MEM_freeN(mvert);
- if (is_init) bm->elem_index_dirty &= ~BM_VERT;
-
- /*do edges*/
- bool edge_allocated;
- me = medge = DM_get_edge_array(dm, &edge_allocated);
- for (i = 0; i < totedge; i++, me++) {
- //BLI_assert(BM_edge_exists(vtable[me->v1], vtable[me->v2]) == NULL);
- e = BM_edge_create(bm, vtable[me->v1], vtable[me->v2], NULL, BM_CREATE_SKIP_CD);
-
- e->head.hflag = BM_edge_flag_from_mflag(me->flag);
- BM_elem_index_set(e, i); /* set_inline */
-
- CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data, true);
- etable[i] = e;
-
- if (cd_edge_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)me->bweight / 255.0f);
- if (cd_edge_crease_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)me->crease / 255.0f);
-
- if (UNLIKELY(has_orig_htype & BM_EDGE)) {
- int *orig_index = CustomData_bmesh_get(&bm->edata, e->head.data, CD_ORIGINDEX);
- *orig_index = ORIGINDEX_NONE;
- }
- }
- if (edge_allocated) MEM_freeN(medge);
- if (is_init) bm->elem_index_dirty &= ~BM_EDGE;
-
- /* do faces */
- /* note: i_alt is aligned with bmesh faces which may not always align with mpolys */
- bool poly_allocated, loop_allocated;
- mpoly = mp = DM_get_poly_array(dm, &poly_allocated);
- mloop = DM_get_loop_array(dm, &loop_allocated);
- face_normals = (dm->dirty & DM_DIRTY_NORMALS) ? NULL : CustomData_get_layer(&dm->polyData, CD_NORMAL);
- for (i = 0; i < dm->numPolyData; i++, mp++) {
- BMLoop *l_iter;
- BMLoop *l_first;
-
- f = bm_face_create_from_mpoly(mp, mloop + mp->loopstart,
- bm, vtable, etable);
-
- if (UNLIKELY(f == NULL)) {
- continue;
- }
-
- f->head.hflag = BM_face_flag_from_mflag(mp->flag);
- BM_elem_index_set(f, bm->totface - 1); /* set_inline */
- f->mat_nr = mp->mat_nr;
-
- j = mp->loopstart;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- /* Save index of correspsonding MLoop */
- CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, j, &l_iter->head.data, true);
- BM_elem_index_set(l_iter, j++); /* set_inline */
- } while ((l_iter = l_iter->next) != l_first);
-
- CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, i, &f->head.data, true);
-
- if (calc_face_normal) {
- if (face_normals) {
- copy_v3_v3(f->no, face_normals[i]);
- }
- else {
- BM_face_normal_update(f);
- }
- }
-
- if (UNLIKELY(has_orig_htype & BM_FACE)) {
- int *orig_index = CustomData_bmesh_get(&bm->pdata, f->head.data, CD_ORIGINDEX);
- *orig_index = ORIGINDEX_NONE;
- }
- }
- if (poly_allocated) MEM_freeN(mpoly);
- if (loop_allocated) MEM_freeN(mloop);
- if (is_init) bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP);
-
- MEM_freeN(vtable);
- MEM_freeN(etable);
-}
-
-/* converts a cddm to a BMEditMesh. if existing is non-NULL, the
- * new geometry will be put in there.*/
-BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do_tessellate)
-{
- BMEditMesh *em = existing;
- BMesh *bm;
-
- if (em) {
- bm = em->bm;
- }
- else {
- bm = BM_mesh_create(
- &bm_mesh_allocsize_default,
- &((struct BMeshCreateParams){.use_toolflags = false,}));
- }
-
- DM_to_bmesh_ex(dm, bm, do_tessellate);
-
- if (!em) {
- em = BKE_editmesh_create(bm, do_tessellate);
- }
- else {
- if (do_tessellate) {
- BKE_editmesh_tessface_calc(em);
- }
- }
-
- return em;
-}
-
-BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal)
-{
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm);
-
- bm = BM_mesh_create(
- &allocsize,
- &((struct BMeshCreateParams){.use_toolflags = false,}));
-
- DM_to_bmesh_ex(dm, bm, calc_face_normal);
-
- return bm;
-}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index a11b0c62aa8..0117b36a16e 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1162,6 +1162,7 @@ void BKE_movieclip_get_size(MovieClip *clip, MovieClipUser *user, int *width, in
* cache lookups and even unwanted non-proxied files loading when doing mask parenting,
* so let's disable this for now and assume image sequence consists of images with
* equal sizes (sergey)
+ * TODO(sergey): Support reading sequences of different resolution.
*/
if (user->framenr == clip->lastframe) {
#endif
@@ -1609,8 +1610,51 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip,
return result;
}
-void BKE_movieclip_eval_update(struct EvaluationContext *UNUSED(eval_ctx), MovieClip *clip)
+static void movieclip_selection_synchronize(MovieClip *clip_dst, const MovieClip *clip_src)
{
- DEG_debug_print_eval(__func__, clip->id.name, clip);
+ BLI_assert(clip_dst != clip_src);
+ MovieTracking *tracking_dst = &clip_dst->tracking, tracking_src = clip_src->tracking;
+ /* Syncs the active object, track and plane track. */
+ tracking_dst->objectnr = tracking_src.objectnr;
+ const int active_track_index = BLI_findindex(&tracking_src.tracks, tracking_src.act_track);
+ const int active_plane_track_index = BLI_findindex(&tracking_src.plane_tracks, tracking_src.act_plane_track);
+ tracking_dst->act_track = BLI_findlink(&tracking_dst->tracks, active_track_index);
+ tracking_dst->act_plane_track = BLI_findlink(&tracking_dst->plane_tracks, active_plane_track_index);
+
+ /* Syncs the tracking selection flag. */
+ MovieTrackingObject *tracking_object_dst, *tracking_object_src;
+ tracking_object_src = tracking_src.objects.first;
+
+ for (tracking_object_dst = tracking_dst->objects.first;
+ tracking_object_dst != NULL;
+ tracking_object_dst = tracking_object_dst->next,
+ tracking_object_src = tracking_object_src->next)
+ {
+ ListBase *tracksbase_dst, *tracksbase_src;
+ tracksbase_dst = BKE_tracking_object_get_tracks(tracking_dst, tracking_object_dst);
+ tracksbase_src = BKE_tracking_object_get_tracks(&tracking_src, tracking_object_src);
+
+ MovieTrackingTrack *track_dst, *track_src;
+ track_src = tracksbase_src->first;
+ for (track_dst = tracksbase_dst->first;
+ track_dst != NULL;
+ track_dst = track_dst->next, track_src = track_src->next)
+ {
+ track_dst->flag = track_src->flag;
+ track_dst->pat_flag = track_src->pat_flag;
+ track_dst->search_flag = track_src->search_flag;
+ }
+ }
+}
+
+void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, MovieClip *clip)
+{
+ DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
BKE_tracking_dopesheet_tag_update(&clip->tracking);
}
+
+void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, MovieClip *clip)
+{
+ DEG_debug_print_eval(depsgraph, __func__, clip->id.name, clip);
+ movieclip_selection_synchronize(clip, (MovieClip *)clip->id.orig_id);
+}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 279c6eb0c82..8f02b51fd5f 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -49,12 +49,15 @@
#include "BKE_pbvh.h"
#include "BKE_ccg.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
+#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
#include "BKE_editmesh.h"
@@ -62,6 +65,8 @@
#include "CCGSubSurf.h"
+#include "DEG_depsgraph_query.h"
+
#include <math.h>
#include <string.h>
@@ -277,14 +282,14 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level)
return mdisps;
}
-DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
+DerivedMesh *get_multires_dm(struct Depsgraph *depsgraph, Scene *scene, MultiresModifierData *mmd, Object *ob)
{
ModifierData *md = (ModifierData *)mmd;
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- DerivedMesh *tdm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+ DerivedMesh *tdm = mesh_get_derived_deform(depsgraph, scene, ob, CD_MASK_BAREMESH);
DerivedMesh *dm;
+ ModifierEvalContext mectx = {depsgraph, ob, MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY};
- dm = mti->applyModifier(md, ob, tdm, MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY);
+ dm = modifier_applyModifier_DM_deprecated(md, &mectx, tdm);
if (dm == tdm) {
dm = CDDM_copy(tdm);
}
@@ -292,6 +297,28 @@ DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob
return dm;
}
+Mesh *BKE_multires_create_mesh(
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ MultiresModifierData *mmd,
+ Object *ob)
+{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *deformed_mesh = mesh_get_eval_deform(depsgraph, scene, ob_eval, CD_MASK_BAREMESH);
+ ModifierEvalContext modifier_ctx = {
+ .depsgraph = depsgraph,
+ .object = ob_eval,
+ .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY};
+
+ const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type);
+ Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh);
+
+ if (result == deformed_mesh) {
+ result = BKE_mesh_copy_for_eval(deformed_mesh, true);
+ }
+ return result;
+}
+
MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd)
{
ModifierData *md;
@@ -336,17 +363,17 @@ MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_f
return mmd;
}
-static int multires_get_level(Object *ob, MultiresModifierData *mmd,
- bool render, bool ignore_simplify)
+int multires_get_level(const Scene *scene, const Object *ob, const MultiresModifierData *mmd,
+ bool render, bool ignore_simplify)
{
if (render)
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl, true) : mmd->renderlvl;
+ return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->renderlvl, true) : mmd->renderlvl;
else if (ob->mode == OB_MODE_SCULPT)
return mmd->sculptlvl;
else if (ignore_simplify)
return mmd->lvl;
else
- return (mmd->modifier.scene) ? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl, false) : mmd->lvl;
+ return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->lvl, false) : mmd->lvl;
}
void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl)
@@ -366,21 +393,49 @@ static void multires_dm_mark_as_modified(DerivedMesh *dm, MultiresModifiedFlags
ccgdm->multires.modified_flags |= flags;
}
+static void multires_ccg_mark_as_modified(SubdivCCG *subdiv_ccg,
+ MultiresModifiedFlags flags)
+{
+ if (flags & MULTIRES_COORDS_MODIFIED) {
+ subdiv_ccg->dirty.coords = true;
+ }
+ if (flags & MULTIRES_HIDDEN_MODIFIED) {
+ subdiv_ccg->dirty.hidden = true;
+ }
+}
+
void multires_mark_as_modified(Object *ob, MultiresModifiedFlags flags)
{
- if (ob && ob->derivedFinal)
- multires_dm_mark_as_modified(ob->derivedFinal, flags);
+ if (ob == NULL) {
+ return;
+ }
+ Mesh *mesh = ob->data;
+ SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg;
+ if (subdiv_ccg == NULL) {
+ return;
+ }
+ multires_ccg_mark_as_modified(subdiv_ccg, flags);
}
void multires_force_update(Object *ob)
{
- if (ob) {
- BKE_object_free_derived_caches(ob);
-
- if (ob->sculpt && ob->sculpt->pbvh) {
- BKE_pbvh_free(ob->sculpt->pbvh);
- ob->sculpt->pbvh = NULL;
+ if (ob == NULL) {
+ return;
+ }
+ SculptSession *sculpt_session = ob->sculpt;
+ if (sculpt_session != NULL && sculpt_session->pbvh != NULL) {
+ PBVH *pbvh = sculpt_session->pbvh;
+ if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) {
+ Mesh *mesh = ob->data;
+ multiresModifier_reshapeFromCCG(
+ sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg);
+ }
+ else {
+ /* NOTE: Disabled for until OpenSubdiv is enabled by default. */
+ // BLI_assert(!"multires_force_update is used on non-grids PBVH");
}
+ BKE_pbvh_free(pbvh);
+ ob->sculpt->pbvh = NULL;
}
}
@@ -398,68 +453,6 @@ void multires_force_render_update(Object *ob)
multires_force_update(ob);
}
-int multiresModifier_reshapeFromDM(Scene *scene, MultiresModifierData *mmd,
- Object *ob, DerivedMesh *srcdm)
-{
- DerivedMesh *mrdm = get_multires_dm(scene, mmd, ob);
-
- if (mrdm && srcdm && mrdm->getNumVerts(mrdm) == srcdm->getNumVerts(srcdm)) {
- multires_mvert_to_ss(mrdm, srcdm->getVertArray(srcdm));
-
- multires_dm_mark_as_modified(mrdm, MULTIRES_COORDS_MODIFIED);
- multires_force_update(ob);
-
- mrdm->release(mrdm);
-
- return 1;
- }
-
- if (mrdm) mrdm->release(mrdm);
-
- return 0;
-}
-
-/* Returns 1 on success, 0 if the src's totvert doesn't match */
-int multiresModifier_reshape(Scene *scene, MultiresModifierData *mmd, Object *dst, Object *src)
-{
- DerivedMesh *srcdm = mesh_get_derived_final(scene, src, CD_MASK_BAREMESH);
- return multiresModifier_reshapeFromDM(scene, mmd, dst, srcdm);
-}
-
-int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mmd,
- Object *ob, ModifierData *md)
-{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- DerivedMesh *dm, *ndm;
- int numVerts, result;
- float (*deformedVerts)[3];
-
- if (multires_get_level(ob, mmd, false, true) == 0)
- return 0;
-
- /* Create DerivedMesh for deformation modifier */
- dm = get_multires_dm(scene, mmd, ob);
- numVerts = dm->getNumVerts(dm);
- deformedVerts = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "multiresReshape_deformVerts");
-
- dm->getVertCos(dm, deformedVerts);
- mti->deformVerts(md, ob, dm, deformedVerts, numVerts, 0);
-
- ndm = CDDM_copy(dm);
- CDDM_apply_vert_coords(ndm, deformedVerts);
-
- MEM_freeN(deformedVerts);
- dm->release(dm);
-
- /* Reshaping */
- result = multiresModifier_reshapeFromDM(scene, mmd, ob, ndm);
-
- /* Cleanup */
- ndm->release(ndm);
-
- return result;
-}
-
/* reset the multires levels to match the number of mdisps */
static int get_levels_from_disps(Object *ob)
{
@@ -680,10 +673,10 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
}
/* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */
-void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int direction)
+void multiresModifier_del_levels(MultiresModifierData *mmd, Scene *scene, Object *ob, int direction)
{
Mesh *me = BKE_mesh_from_object(ob);
- int lvl = multires_get_level(ob, mmd, false, true);
+ int lvl = multires_get_level(scene, ob, mmd, false, true);
int levels = mmd->totlvl - lvl;
MDisps *mdisps;
@@ -700,7 +693,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire
multires_set_tot_level(ob, mmd, lvl);
}
-static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, bool alloc_paint_mask)
+static DerivedMesh *multires_dm_create_local(Scene *scene, Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, bool alloc_paint_mask)
{
MultiresModifierData mmd = {{NULL}};
MultiresFlags flags = MULTIRES_USE_LOCAL_MMD;
@@ -714,29 +707,44 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv
if (alloc_paint_mask)
flags |= MULTIRES_ALLOC_PAINT_MASK;
- return multires_make_derived_from_derived(dm, &mmd, ob, flags);
+ return multires_make_derived_from_derived(dm, &mmd, scene, ob, flags);
}
-static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal, int plain_uv, int alloc_paint_mask)
+static DerivedMesh *subsurf_dm_create_local(
+ Scene *scene, Object *ob, DerivedMesh *dm,
+ int lvl,
+ bool is_simple, bool is_optimal, bool is_plain_uv, bool alloc_paint_mask,
+ bool for_render)
{
SubsurfModifierData smd = {{NULL}};
SubsurfFlags flags = 0;
smd.levels = smd.renderLevels = lvl;
- if (!plain_uv)
- smd.flags |= eSubsurfModifierFlag_SubsurfUv;
- if (simple)
+ smd.quality = 3;
+ if (!is_plain_uv) {
+ smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
+ }
+ else {
+ smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE;
+ }
+ if (is_simple) {
smd.subdivType = ME_SIMPLE_SUBSURF;
- if (optimal)
+ }
+ if (is_optimal) {
smd.flags |= eSubsurfModifierFlag_ControlEdges;
+ }
- if (ob->mode & OB_MODE_EDIT)
+ if (ob->mode & OB_MODE_EDIT) {
flags |= SUBSURF_IN_EDIT_MODE;
-
- if (alloc_paint_mask)
+ }
+ if (alloc_paint_mask) {
flags |= SUBSURF_ALLOC_PAINT_MASK;
+ }
+ if (for_render) {
+ flags |= SUBSURF_USE_RENDER_PARAMS;
+ }
- return subsurf_make_derived_from_derived(dm, &smd, NULL, flags);
+ return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags);
}
@@ -750,7 +758,7 @@ static float v3_dist_from_plane(float v[3], float center[3], float no[3])
return dot_v3v3(s, no);
}
-void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
+void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object *ob)
{
DerivedMesh *cddm, *dispdm, *origdm;
Mesh *me;
@@ -772,7 +780,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
/* generate highest level with displacements */
cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- dispdm = multires_dm_create_local(ob, cddm, totlvl, totlvl, 0, 0);
+ dispdm = multires_dm_create_local(scene, ob, cddm, totlvl, totlvl, 0, 0);
cddm->release(cddm);
/* copy the new locations of the base verts into the mesh */
@@ -868,7 +876,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
/* subdivide the mesh to highest level without displacements */
cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
+ origdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, 0, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, 0, false);
cddm->release(cddm);
/* calc disps */
@@ -878,7 +886,9 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
dispdm->release(dispdm);
}
-static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl, int updateblock, int simple)
+static void multires_subdivide(
+ MultiresModifierData *mmd, Scene *scene, Object *ob,
+ int totlvl, int updateblock, int simple)
{
Mesh *me = ob->data;
MDisps *mdisps;
@@ -907,11 +917,11 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
/* create subsurf DM from original mesh at high level */
cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
+ highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false);
ss = ((CCGDerivedMesh *)highdm)->ss;
/* create multires DM from original mesh at low level */
- lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask);
+ lowdm = multires_dm_create_local(scene, ob, cddm, lvl, lvl, simple, has_mask);
BLI_assert(lowdm != cddm);
cddm->release(cddm);
@@ -961,9 +971,9 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
multires_set_tot_level(ob, mmd, totlvl);
}
-void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple)
+void multiresModifier_subdivide(MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple)
{
- multires_subdivide(mmd, ob, mmd->totlvl + 1, updateblock, simple);
+ multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple);
}
static void grid_tangent(const CCGKey *key, int x, int y, int axis, CCGElem *grid, float t[3])
@@ -1196,7 +1206,7 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm
}
}
-void multires_modifier_update_mdisps(struct DerivedMesh *dm)
+void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
Object *ob;
@@ -1228,11 +1238,11 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm)
else cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
+ highdm = subsurf_dm_create_local(scene, ob, cddm, totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false);
ss = ((CCGDerivedMesh *)highdm)->ss;
/* create multires DM from original mesh and displacements */
- lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple, has_mask);
+ lowdm = multires_dm_create_local(scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask);
cddm->release(cddm);
/* gather grid data */
@@ -1290,7 +1300,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm)
else cddm = CDDM_from_mesh(me);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
- subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, has_mask);
+ subdm = subsurf_dm_create_local(scene, ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, has_mask, false);
cddm->release(cddm);
multiresModifier_disp_run(dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl);
@@ -1332,147 +1342,36 @@ void multires_modifier_update_hidden(DerivedMesh *dm)
}
}
-void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
+void multires_stitch_grids(Object *ob)
{
- DerivedMesh *ccgdm = NULL, *subsurf = NULL;
- CCGElem **gridData, **subGridData = NULL;
- CCGKey key;
- MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
- MDisps *mdisps;
- MultiresModifierData *mmd = get_multires_modifier(NULL, ob, 1);
- int *gridOffset, totlvl;
- int i, k, numGrids, gridSize, dGridSize, dSkip;
-
- if (!mmd)
+ if (ob == NULL) {
return;
-
- mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
-
- if (!mdisps) {
- goto cleanup;
- }
-
- totlvl = mmd->totlvl;
- ccgdm = multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple, false);
-
- subsurf = subsurf_dm_create_local(ob, dm, totlvl,
- mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
-
- numGrids = subsurf->getNumGrids(subsurf);
- gridSize = subsurf->getGridSize(subsurf);
- gridData = subsurf->getGridData(subsurf);
- subsurf->getGridKey(subsurf, &key);
-
- subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*");
-
- for (i = 0; i < numGrids; i++) {
- subGridData[i] = MEM_calloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData");
- memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize);
- }
-
- /* numGrids = ccgdm->dm->getNumGrids((DerivedMesh *)ccgdm); */ /*UNUSED*/
- gridSize = ccgdm->getGridSize((DerivedMesh *)ccgdm);
- gridData = ccgdm->getGridData((DerivedMesh *)ccgdm);
- gridOffset = ccgdm->getGridOffset((DerivedMesh *)ccgdm);
-
- dGridSize = multires_side_tot[totlvl];
- dSkip = (dGridSize - 1) / (gridSize - 1);
-
- k = 0; /*current loop/mdisp index within the mloop array*/
-
- /* TODO: Use BLI_task parallel range for that one too? */
- for (i = 0; i < dm->numPolyData; ++i) {
- const int numVerts = mpoly[i].totloop;
- int S, x, y, gIndex = gridOffset[i];
-
- for (S = 0; S < numVerts; ++S, ++gIndex, ++k) {
- MDisps *mdisp = &mdisps[mpoly[i].loopstart + S];
- /* CCGElem *grid = gridData[gIndex]; */ /* UNUSED */
- CCGElem *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = NULL;
-
- /* when adding new faces in edit mode, need to allocate disps */
- if (!mdisp->disps) {
- mdisp->totdisp = gridSize * gridSize;
- mdisp->level = totlvl;
- mdisp->disps = MEM_calloc_arrayN(mdisp->totdisp, 3 * sizeof(float), "disp in multires_set_space");
- }
-
- dispgrid = mdisp->disps;
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
- float *co = CCG_grid_elem_co(&key, subgrid, x, y);
- float mat[3][3], dco[3];
-
- /* construct tangent space matrix */
- grid_tangent_matrix(mat, &key, x, y, subgrid);
-
- /* convert to absolute coordinates in space */
- if (from == MULTIRES_SPACE_TANGENT) {
- mul_v3_m3v3(dco, mat, data);
- add_v3_v3(dco, co);
- }
- else if (from == MULTIRES_SPACE_OBJECT) {
- add_v3_v3v3(dco, co, data);
- }
- else if (from == MULTIRES_SPACE_ABSOLUTE) {
- copy_v3_v3(dco, data);
- }
-
- /*now, convert to desired displacement type*/
- if (to == MULTIRES_SPACE_TANGENT) {
- invert_m3(mat);
-
- sub_v3_v3(dco, co);
- mul_v3_m3v3(data, mat, dco);
- }
- else if (to == MULTIRES_SPACE_OBJECT) {
- sub_v3_v3(dco, co);
- mul_v3_m3v3(data, mat, dco);
- }
- else if (to == MULTIRES_SPACE_ABSOLUTE) {
- copy_v3_v3(data, dco);
- }
- }
- }
- }
}
-
-cleanup:
- if (subsurf) {
- subsurf->needsFree = 1;
- subsurf->release(subsurf);
+ SculptSession *sculpt_session = ob->sculpt;
+ if (sculpt_session == NULL) {
+ return;
}
-
- if (ccgdm) {
- ccgdm->needsFree = 1;
- ccgdm->release(ccgdm);
+ PBVH *pbvh = sculpt_session->pbvh;
+ SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg;
+ if (pbvh == NULL || subdiv_ccg == NULL) {
+ return;
}
-}
-
-void multires_stitch_grids(Object *ob)
-{
- /* utility for smooth brush */
- if (ob && ob->derivedFinal) {
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)ob->derivedFinal;
- CCGFace **faces;
- int totface;
-
- if (ccgdm->pbvh) {
- BKE_pbvh_get_grid_updates(ccgdm->pbvh, false, (void ***)&faces, &totface);
-
- if (totface) {
- ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface);
- MEM_freeN(faces);
- }
- }
+ BLI_assert(BKE_pbvh_type(pbvh) == PBVH_GRIDS);
+ /* NOTE: Currently CCG does not keep track of faces, making it impossible
+ * to use BKE_pbvh_get_grid_updates().
+ */
+ CCGFace **faces;
+ int num_faces;
+ BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces);
+ if (num_faces) {
+ BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces);
+ MEM_freeN(faces);
}
}
DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
MultiresModifierData *mmd,
+ Scene *scene,
Object *ob,
MultiresFlags flags)
{
@@ -1483,16 +1382,17 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
CCGKey key;
const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0;
const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0;
- int lvl = multires_get_level(ob, mmd, render, ignore_simplify);
+ int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify);
int i, gridSize, numGrids;
if (lvl == 0)
return dm;
- result = subsurf_dm_create_local(ob, dm, lvl,
+ result = subsurf_dm_create_local(scene, ob, dm, lvl,
mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges,
- mmd->flags & eMultiresModifierFlag_PlainUv,
- flags & MULTIRES_ALLOC_PAINT_MASK);
+ mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE,
+ flags & MULTIRES_ALLOC_PAINT_MASK,
+ render);
if (!(flags & MULTIRES_USE_LOCAL_MMD)) {
ccgdm = (CCGDerivedMesh *)result;
@@ -2168,7 +2068,7 @@ void multires_load_old(Object *ob, Mesh *me)
BLI_insertlinkbefore(&ob->modifiers, md, mmd);
for (i = 0; i < me->mr->level_count - 1; ++i)
- multiresModifier_subdivide(mmd, ob, 1, 0);
+ multiresModifier_subdivide(mmd, NULL, ob, 1, 0);
mmd->lvl = mmd->totlvl;
orig = CDDM_from_mesh(me);
@@ -2177,7 +2077,7 @@ void multires_load_old(Object *ob, Mesh *me)
* reference subsurfed dm with this option, before calling multiresModifier_disp_run(),
* which implicitly expects both subsurfs from its first dm and oldGridData parameters to
* be of the same "format"! */
- dm = multires_make_derived_from_derived(orig, mmd, ob, 0);
+ dm = multires_make_derived_from_derived(orig, mmd, NULL, ob, 0);
multires_load_old_dm(dm, me, mmd->totlvl + 1);
@@ -2192,14 +2092,14 @@ void multires_load_old(Object *ob, Mesh *me)
/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
* such that 'ob_dst' has the same total number of levels as 'ob_src'. */
-void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
+void multiresModifier_sync_levels_ex(Scene *scene, Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
{
if (mmd_src->totlvl == mmd_dst->totlvl) {
return;
}
if (mmd_src->totlvl > mmd_dst->totlvl) {
- multires_subdivide(mmd_dst, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
+ multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
}
else {
multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
@@ -2221,134 +2121,50 @@ static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
}
if (mmd_src && mmd_dst) {
- multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst);
+ multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst);
}
}
-static void multires_apply_smat_cb(
- void *__restrict userdata,
- const int pidx,
- const ParallelRangeTLS *__restrict UNUSED(tls))
+static void multires_apply_uniform_scale(Object *object, const float scale)
{
- MultiresThreadedData *tdata = userdata;
-
- CCGElem **gridData = tdata->gridData;
- CCGElem **subGridData = tdata->subGridData;
- CCGKey *dm_key = tdata->key;
- CCGKey *subdm_key = tdata->sub_key;
- MPoly *mpoly = tdata->mpoly;
- MDisps *mdisps = tdata->mdisps;
- int *gridOffset = tdata->gridOffset;
- int gridSize = tdata->gridSize;
- int dGridSize = tdata->dGridSize;
- int dSkip = tdata->dSkip;
- float (*smat)[3] = tdata->smat;
-
- const int numVerts = mpoly[pidx].totloop;
- MDisps *mdisp = &mdisps[mpoly[pidx].loopstart];
- int S, x, y, gIndex = gridOffset[pidx];
-
- for (S = 0; S < numVerts; ++S, ++gIndex, mdisp++) {
- CCGElem *grid = gridData[gIndex];
- CCGElem *subgrid = subGridData[gIndex];
- float (*dispgrid)[3] = mdisp->disps;
-
- for (y = 0; y < gridSize; y++) {
- for (x = 0; x < gridSize; x++) {
- float *co = CCG_grid_elem_co(dm_key, grid, x, y);
- float *sco = CCG_grid_elem_co(subdm_key, subgrid, x, y);
- float *data = dispgrid[dGridSize * y * dSkip + x * dSkip];
- float mat[3][3], disp[3];
-
- /* construct tangent space matrix */
- grid_tangent_matrix(mat, dm_key, x, y, grid);
-
- /* scale subgrid coord and calculate displacement */
- mul_m3_v3(smat, sco);
- sub_v3_v3v3(disp, sco, co);
-
- /* convert difference to tangent space */
- invert_m3(mat);
- mul_v3_m3v3(data, mat, disp);
- }
+ Mesh *mesh = (Mesh *)object->data;
+ MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ for (int i = 0; i < mesh->totloop; ++i) {
+ MDisps *grid = &mdisps[i];
+ for (int j = 0; j < grid->totdisp; ++j) {
+ mul_v3_fl(grid->disps[j], scale);
}
}
}
-static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
+static void multires_apply_smat(
+ struct Depsgraph *UNUSED(depsgraph),
+ Scene *scene,
+ Object *object,
+ float smat[3][3])
{
- DerivedMesh *dm = NULL, *cddm = NULL, *subdm = NULL;
- CCGElem **gridData, **subGridData;
- CCGKey dm_key, subdm_key;
- Mesh *me = (Mesh *)ob->data;
- MPoly *mpoly = me->mpoly;
- /* MLoop *mloop = me->mloop; */ /* UNUSED */
- MDisps *mdisps;
- int *gridOffset;
- int i, /*numGrids, */ gridSize, dGridSize, dSkip, totvert;
- float (*vertCos)[3] = NULL;
- MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1);
- MultiresModifierData high_mmd;
-
- CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
- mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
-
- if (!mdisps || !mmd || !mmd->totlvl) return;
-
- /* we need derived mesh created from highest resolution */
- high_mmd = *mmd;
- high_mmd.lvl = high_mmd.totlvl;
-
- /* unscaled multires with applied displacement */
- subdm = get_multires_dm(scene, &high_mmd, ob);
-
- /* prepare scaled CDDM to create ccgDN */
- cddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
-
- totvert = cddm->getNumVerts(cddm);
- vertCos = MEM_malloc_arrayN(totvert, sizeof(*vertCos), "multiresScale vertCos");
- cddm->getVertCos(cddm, vertCos);
- for (i = 0; i < totvert; i++)
- mul_m3_v3(smat, vertCos[i]);
- CDDM_apply_vert_coords(cddm, vertCos);
- MEM_freeN(vertCos);
-
- /* scaled ccgDM for tangent space of object with applied scale */
- dm = subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0);
- cddm->release(cddm);
-
- gridSize = dm->getGridSize(dm);
- gridData = dm->getGridData(dm);
- gridOffset = dm->getGridOffset(dm);
- dm->getGridKey(dm, &dm_key);
- subGridData = subdm->getGridData(subdm);
- subdm->getGridKey(subdm, &subdm_key);
-
- dGridSize = multires_side_tot[high_mmd.totlvl];
- dSkip = (dGridSize - 1) / (gridSize - 1);
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.min_iter_per_thread = CCG_TASK_LIMIT;
-
- MultiresThreadedData data = {
- .gridData = gridData,
- .subGridData = subGridData,
- .key = &dm_key,
- .sub_key = &subdm_key,
- .mpoly = mpoly,
- .mdisps = mdisps,
- .gridOffset = gridOffset,
- .gridSize = gridSize,
- .dGridSize = dGridSize,
- .dSkip = dSkip,
- .smat = smat
- };
-
- BLI_task_parallel_range(0, me->totpoly, &data, multires_apply_smat_cb, &settings);
-
- dm->release(dm);
- subdm->release(subdm);
+ const MultiresModifierData *mmd = get_multires_modifier(scene, object, true);
+ if (mmd == NULL || mmd->totlvl == 0) {
+ return;
+ }
+ /* Make sure layer present. */
+ Mesh *mesh = (Mesh *)object->data;
+ CustomData_external_read(
+ &mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop);
+ if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) {
+ return;
+ }
+ if (is_uniform_scaled_m3(smat)) {
+ const float scale = mat3_to_scale(smat);
+ multires_apply_uniform_scale(object, scale);
+ }
+ else {
+ /* TODO(sergey): This branch of code actually requires more work to
+ * preserve all the details.
+ */
+ const float scale = mat3_to_scale(smat);
+ multires_apply_uniform_scale(object, scale);
+ }
}
int multires_mdisp_corners(MDisps *s)
@@ -2364,17 +2180,17 @@ int multires_mdisp_corners(MDisps *s)
return 0;
}
-void multiresModifier_scale_disp(Scene *scene, Object *ob)
+void multiresModifier_scale_disp(struct Depsgraph *depsgraph, Scene *scene, Object *ob)
{
float smat[3][3];
/* object's scale matrix */
BKE_object_scale_to_mat3(ob, smat);
- multires_apply_smat(scene, ob, smat);
+ multires_apply_smat(depsgraph, scene, ob, smat);
}
-void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
+void multiresModifier_prepare_join(struct Depsgraph *depsgraph, Scene *scene, Object *ob, Object *to_ob)
{
float smat[3][3], tmat[3][3], mat[3][3];
multires_sync_levels(scene, to_ob, ob);
@@ -2385,7 +2201,7 @@ void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
BKE_object_scale_to_mat3(ob, smat);
mul_m3_m3m3(mat, smat, tmat);
- multires_apply_smat(scene, ob, mat);
+ multires_apply_smat(depsgraph, scene, ob, mat);
}
/* update multires data after topology changing */
diff --git a/source/blender/blenkernel/intern/multires_inline.h b/source/blender/blenkernel/intern/multires_inline.h
new file mode 100644
index 00000000000..99b4695fe46
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_inline.h
@@ -0,0 +1,68 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/multires_inline.h
+ * \ingroup bke
+ */
+
+#ifndef __MULTIRES_INLINE_H__
+#define __MULTIRES_INLINE_H__
+
+#include "BKE_multires.h"
+#include "BLI_math_vector.h"
+
+BLI_INLINE void BKE_multires_construct_tangent_matrix(
+ float tangent_matrix[3][3],
+ const float dPdu[3],
+ const float dPdv[3],
+ const int corner)
+{
+ if (corner == 0) {
+ copy_v3_v3(tangent_matrix[0], dPdv);
+ copy_v3_v3(tangent_matrix[1], dPdu);
+ mul_v3_fl(tangent_matrix[0], -1.0f);
+ mul_v3_fl(tangent_matrix[1], -1.0f);
+ }
+ else if (corner == 1) {
+ copy_v3_v3(tangent_matrix[0], dPdu);
+ copy_v3_v3(tangent_matrix[1], dPdv);
+ mul_v3_fl(tangent_matrix[1], -1.0f);
+ }
+ else if (corner == 2) {
+ copy_v3_v3(tangent_matrix[0], dPdv);
+ copy_v3_v3(tangent_matrix[1], dPdu);
+ }
+ else if (corner == 3) {
+ copy_v3_v3(tangent_matrix[0], dPdu);
+ copy_v3_v3(tangent_matrix[1], dPdv);
+ mul_v3_fl(tangent_matrix[0], -1.0f);
+ }
+ cross_v3_v3v3(tangent_matrix[2], dPdu, dPdv);
+ normalize_v3(tangent_matrix[0]);
+ normalize_v3(tangent_matrix[1]);
+ normalize_v3(tangent_matrix[2]);
+}
+
+#endif /* __MULTIRES_INLINE_H__ */
diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c
new file mode 100644
index 00000000000..fe4bc5ca3e0
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_reshape.c
@@ -0,0 +1,1206 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/multires_reshape.c
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_task.h"
+
+#include "BKE_ccg.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
+
+#include "DEG_depsgraph_query.h"
+
+static void multires_reshape_init_mmd(
+ MultiresModifierData *reshape_mmd,
+ const MultiresModifierData *mmd)
+{
+ *reshape_mmd = *mmd;
+}
+
+static void multires_reshape_init_mmd_top_level(
+ MultiresModifierData *reshape_mmd,
+ const MultiresModifierData *mmd)
+{
+ *reshape_mmd = *mmd;
+ reshape_mmd->lvl = reshape_mmd->totlvl;
+}
+
+/* =============================================================================
+ * General reshape implementation, reused by all particular cases.
+ */
+
+typedef struct MultiresReshapeContext {
+ Subdiv *subdiv;
+ const Mesh *coarse_mesh;
+ MDisps *mdisps;
+ GridPaintMask *grid_paint_mask;
+ int top_grid_size;
+ int top_level;
+} MultiresReshapeContext;
+
+static void multires_reshape_allocate_displacement_grid(
+ MDisps *displacement_grid, const int level)
+{
+ const int grid_size = BKE_subdiv_grid_size_from_level(level);
+ const int grid_area = grid_size * grid_size;
+ float (*disps)[3] = MEM_calloc_arrayN(
+ grid_area, 3 * sizeof(float), "multires disps");
+ displacement_grid->disps = disps;
+ displacement_grid->totdisp = grid_area;
+ displacement_grid->level = level;
+}
+
+static void multires_reshape_ensure_displacement_grid(
+ MDisps *displacement_grid, const int level)
+{
+ if (displacement_grid->disps != NULL) {
+ return;
+ }
+ multires_reshape_allocate_displacement_grid(
+ displacement_grid, level);
+}
+
+static void multires_reshape_ensure_displacement_grids(
+ Mesh *mesh,
+ const int grid_level)
+{
+ const int num_grids = mesh->totloop;
+ MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ multires_reshape_ensure_displacement_grid(
+ &mdisps[grid_index], grid_level);
+ }
+}
+
+static void multires_reshape_ensure_mask_grids(Mesh *mesh, const int grid_level)
+{
+ GridPaintMask *grid_paint_masks =
+ CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ if (grid_paint_masks == NULL) {
+ return;
+ }
+ const int num_grids = mesh->totloop;
+ const int grid_size = BKE_subdiv_grid_size_from_level(grid_level);
+ const int grid_area = grid_size * grid_size;
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
+ if (grid_paint_mask->level == grid_level) {
+ continue;
+ }
+ grid_paint_mask->level = grid_level;
+ if (grid_paint_mask->data) {
+ MEM_freeN(grid_paint_mask->data);
+ }
+ grid_paint_mask->data = MEM_calloc_arrayN(
+ grid_area, sizeof(float), "gpm.data");
+ }
+}
+
+static void multires_reshape_ensure_grids(Mesh *mesh, const int grid_level)
+{
+ multires_reshape_ensure_displacement_grids(mesh, grid_level);
+ multires_reshape_ensure_mask_grids(mesh, grid_level);
+}
+
+static void multires_reshape_vertex_copy_to_next(
+ MultiresReshapeContext *ctx,
+ const MPoly *coarse_poly,
+ const int current_corner,
+ const MDisps *current_displacement_grid,
+ const GridPaintMask *current_mask_grid,
+ const int current_grid_x, const int current_grid_y)
+{
+ const int grid_size = ctx->top_grid_size;
+ const int next_current_corner = (current_corner + 1) % coarse_poly->totloop;
+ const int next_grid_x = 0;
+ const int next_grid_y = current_grid_x;
+ const int current_index = current_grid_y * grid_size + current_grid_x;
+ const int next_index = next_grid_y * grid_size + next_grid_x;
+ /* Copy displacement. */
+ MDisps *next_displacement_grid = &ctx->mdisps[
+ coarse_poly->loopstart + next_current_corner];
+ float *next_displacement = next_displacement_grid->disps[next_index];
+ copy_v3_v3(next_displacement,
+ current_displacement_grid->disps[current_index]);
+ SWAP(float, next_displacement[0], next_displacement[1]);
+ next_displacement[0] = -next_displacement[0];
+ /* Copy mask, if exists. */
+ if (current_mask_grid != NULL) {
+ GridPaintMask *next_mask_grid = &ctx->grid_paint_mask[
+ coarse_poly->loopstart + next_current_corner];
+ next_mask_grid->data[next_index] =
+ current_mask_grid->data[current_index];
+ }
+}
+
+static void multires_reshape_vertex_copy_to_prev(
+ MultiresReshapeContext *ctx,
+ const MPoly *coarse_poly,
+ const int current_corner,
+ const MDisps *current_displacement_grid,
+ const GridPaintMask *current_mask_grid,
+ const int current_grid_x, const int current_grid_y)
+{
+ const int grid_size = ctx->top_grid_size;
+ const int prev_current_corner =
+ (current_corner - 1 + coarse_poly->totloop) % coarse_poly->totloop;
+ const int prev_grid_x = current_grid_y;
+ const int prev_grid_y = 0;
+ const int current_index = current_grid_y * grid_size + current_grid_x;
+ const int prev_index = prev_grid_y * grid_size + prev_grid_x;
+ /* Copy displacement. */
+ MDisps *prev_displacement_grid = &ctx->mdisps[
+ coarse_poly->loopstart + prev_current_corner];
+ float *prev_displacement = prev_displacement_grid->disps[prev_index];
+ copy_v3_v3(prev_displacement,
+ current_displacement_grid->disps[current_index]);
+ SWAP(float, prev_displacement[0], prev_displacement[1]);
+ prev_displacement[1] = -prev_displacement[1];
+ /* Copy mask, if exists. */
+ if (current_mask_grid != NULL) {
+ GridPaintMask *prev_mask_grid = &ctx->grid_paint_mask[
+ coarse_poly->loopstart + prev_current_corner];
+ prev_mask_grid->data[prev_index] =
+ current_mask_grid->data[current_index];
+ }
+}
+
+static void copy_boundary_displacement(
+ MultiresReshapeContext *ctx,
+ const MPoly *coarse_poly,
+ const int corner,
+ const int grid_x, const int grid_y,
+ const MDisps *displacement_grid,
+ const GridPaintMask *mask_grid)
+{
+ if (grid_x == 0 && grid_y == 0) {
+ for (int i = 0; i < coarse_poly->totloop; i++) {
+ const int current_face_corner =
+ (corner + i) % coarse_poly->totloop;
+ const int grid_index = coarse_poly->loopstart + current_face_corner;
+ MDisps *current_displacement_grid = &ctx->mdisps[grid_index];
+ GridPaintMask *current_mask_grid =
+ mask_grid != NULL ? &ctx->grid_paint_mask[grid_index]
+ : NULL;
+ multires_reshape_vertex_copy_to_next(
+ ctx,
+ coarse_poly,
+ current_face_corner,
+ current_displacement_grid,
+ current_mask_grid,
+ 0, 0);
+ }
+ }
+ else if (grid_x == 0) {
+ multires_reshape_vertex_copy_to_prev(
+ ctx,
+ coarse_poly,
+ corner,
+ displacement_grid,
+ mask_grid,
+ grid_x, grid_y);
+ }
+ else if (grid_y == 0) {
+ multires_reshape_vertex_copy_to_next(
+ ctx,
+ coarse_poly,
+ corner,
+ displacement_grid,
+ mask_grid,
+ grid_x, grid_y);
+ }
+}
+
+static void multires_reshape_vertex_from_final_data(
+ MultiresReshapeContext *ctx,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const float final_P[3], const float final_mask)
+{
+ Subdiv *subdiv = ctx->subdiv;
+ const int grid_size = ctx->top_grid_size;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ const int loop_index = coarse_poly->loopstart + coarse_corner;
+ /* Evaluate limit surface. */
+ float P[3], dPdu[3], dPdv[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, u, v, P, dPdu, dPdv);
+ /* Get coordinate and corner configuration. */
+ float grid_u, grid_v;
+ MDisps *displacement_grid;
+ GridPaintMask *grid_paint_mask = NULL;
+ int face_corner = coarse_corner;
+ int grid_corner = 0;
+ int grid_index;
+ if (coarse_poly->totloop == 4) {
+ float corner_u, corner_v;
+ face_corner = BKE_subdiv_rotate_quad_to_corner(
+ u, v, &corner_u, &corner_v);
+ grid_corner = face_corner;
+ grid_index = loop_index + face_corner;
+ BKE_subdiv_ptex_face_uv_to_grid_uv(
+ corner_u, corner_v, &grid_u, &grid_v);
+ }
+ else {
+ grid_index = loop_index;
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, &grid_u, &grid_v);
+ }
+ displacement_grid = &ctx->mdisps[grid_index];
+ if (ctx->grid_paint_mask != NULL) {
+ grid_paint_mask = &ctx->grid_paint_mask[grid_index];
+ BLI_assert(grid_paint_mask->level == displacement_grid->level);
+ }
+ /* Convert object coordinate to a tangent space of displacement grid. */
+ float D[3];
+ sub_v3_v3v3(D, final_P, P);
+ float tangent_matrix[3][3];
+ BKE_multires_construct_tangent_matrix(
+ tangent_matrix, dPdu, dPdv, grid_corner);
+ float inv_tangent_matrix[3][3];
+ invert_m3_m3(inv_tangent_matrix, tangent_matrix);
+ float tangent_D[3];
+ mul_v3_m3v3(tangent_D, inv_tangent_matrix, D);
+ /* Write tangent displacement. */
+ const int grid_x = (grid_u * (grid_size - 1) + 0.5f);
+ const int grid_y = (grid_v * (grid_size - 1) + 0.5f);
+ const int index = grid_y * grid_size + grid_x;
+ copy_v3_v3(displacement_grid->disps[index], tangent_D);
+ /* Write mask grid. */
+ if (grid_paint_mask != NULL) {
+ grid_paint_mask->data[index] = final_mask;
+ }
+ /* Copy boundary to the next/previous grids */
+ copy_boundary_displacement(
+ ctx, coarse_poly, face_corner, grid_x, grid_y,
+ displacement_grid, grid_paint_mask);
+}
+
+/* =============================================================================
+ * Helpers to propagate displacement to higher levels.
+ */
+
+typedef struct MultiresPropagateData {
+ /* Number of displacement grids. */
+ int num_grids;
+ /* Resolution level up to which displacement is known. */
+ int reshape_level;
+ /* Resolution up to which propagation is happening, affecting all the
+ * levels in [reshape_level + 1, top_level].
+ */
+ int top_level;
+ /* Grid sizes at the corresponding levels. */
+ int reshape_grid_size;
+ int top_grid_size;
+ /* Keys to access CCG at different levels. */
+ CCGKey reshape_level_key;
+ CCGKey top_level_key;
+ /* Original grid data, before any updates for reshape.
+ * Contains data at the reshape_level resolution level.
+ */
+ CCGElem **orig_grids_data;
+ /* Custom data layers from a coarse mesh. */
+ MDisps *mdisps;
+ GridPaintMask *grid_paint_mask;
+} MultiresPropagateData;
+
+static CCGElem **allocate_grids(CCGKey *key, int num_grids)
+{
+ CCGElem **grids = MEM_calloc_arrayN(
+ num_grids, sizeof(CCGElem *), "reshape grids*");
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ grids[grid_index] = MEM_calloc_arrayN(
+ key->elem_size,
+ key->grid_area,
+ "reshape orig_grids_data elems");
+ }
+ return grids;
+}
+
+static void free_grids(CCGElem **grids, int num_grids)
+{
+ if (grids == NULL) {
+ return;
+ }
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ MEM_freeN(grids[grid_index]);
+ }
+ MEM_freeN(grids);
+}
+
+/* Initialize element sizes and offsets. */
+static void multires_reshape_init_key_layers(
+ CCGKey *key,
+ const MultiresPropagateData *data)
+{
+ key->elem_size = 3 * sizeof(float);
+ if (data->grid_paint_mask != NULL) {
+ key->mask_offset = 3 * sizeof(float);
+ key->elem_size += sizeof(float);
+ key->has_mask = true;
+ }
+ else {
+ key->mask_offset = -1;
+ key->has_mask = false;
+ }
+ /* We never have normals in original grids. */
+ key->normal_offset = -1;
+ key->has_normals = false;
+}
+
+/* Initialize key used to access reshape grids at given level. */
+static void multires_reshape_init_level_key(
+ CCGKey *key,
+ const MultiresPropagateData *data,
+ const int level)
+{
+ key->level = level;
+ /* Init layers. */
+ multires_reshape_init_key_layers(key, data);
+ /* By default, only 3 floats for coordinate, */
+ key->grid_size = BKE_subdiv_grid_size_from_level(key->level);
+ key->grid_area = key->grid_size * key->grid_size;
+ key->grid_bytes = key->elem_size * key->grid_area;
+}
+
+static void multires_reshape_store_original_grids(
+ MultiresPropagateData *data)
+{
+ const int num_grids = data->num_grids;
+ /* Original data to be backed up. */
+ const MDisps *mdisps = data->mdisps;
+ const GridPaintMask *grid_paint_mask = data->grid_paint_mask;
+ /* Allocate grids for backup. */
+ CCGKey *orig_key = &data->reshape_level_key;
+ CCGElem **orig_grids_data = allocate_grids(orig_key, num_grids);
+ /* Fill in grids. */
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *orig_grid = orig_grids_data[grid_index];
+ for (int y = 0; y < orig_grid_size; y++) {
+ const int top_y = y * skip;
+ for (int x = 0; x < orig_grid_size; x++) {
+ const int top_x = x * skip;
+ const int top_index = top_y * top_grid_size + top_x;
+ memcpy(CCG_grid_elem_co(orig_key, orig_grid, x, y),
+ mdisps[grid_index].disps[top_index],
+ sizeof(float) * 3);
+ if (orig_key->has_mask) {
+ *CCG_grid_elem_mask(orig_key, orig_grid, x, y) =
+ grid_paint_mask[grid_index].data[top_index];
+ }
+ }
+ }
+ }
+ /* Store in the context. */
+ data->orig_grids_data = orig_grids_data;
+}
+
+static void multires_reshape_propagate_prepare(
+ MultiresPropagateData *data,
+ Mesh *coarse_mesh,
+ const int reshape_level,
+ const int top_level)
+{
+ BLI_assert(reshape_level <= top_level);
+ memset(data, 0, sizeof(*data));
+ data->num_grids = coarse_mesh->totloop;
+ data->reshape_level = reshape_level;
+ data->top_level = top_level;
+ if (reshape_level == top_level) {
+ /* Nothing to do, reshape will happen on the whole grid content. */
+ return;
+ }
+ data->mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
+ data->grid_paint_mask =
+ CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK);
+ data->top_grid_size = BKE_subdiv_grid_size_from_level(top_level);
+ data->reshape_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
+ /* Initialize keys to access CCG at different levels. */
+ multires_reshape_init_level_key(
+ &data->reshape_level_key, data, data->reshape_level);
+ multires_reshape_init_level_key(
+ &data->top_level_key, data, data->top_level);
+ /* Make a copy of grids before reshaping, so we can calculate deltas
+ * later on.
+ */
+ multires_reshape_store_original_grids(data);
+}
+
+static void multires_reshape_propagate_prepare_from_mmd(
+ MultiresPropagateData *data,
+ struct Depsgraph *depsgraph,
+ Object *object,
+ const MultiresModifierData *mmd,
+ const int top_level,
+ const bool use_render_params)
+{
+ /* TODO(sergey): Find mode reliable way of getting current level. */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Mesh *mesh = object->data;
+ const int level = multires_get_level(
+ scene_eval, object, mmd, use_render_params, true);
+ multires_reshape_propagate_prepare(data, mesh, level, top_level);
+}
+
+/* Calculate delta of changed reshape level data layers. Delta goes to a
+ * grids at top level (meaning, the result grids are only partially filled
+ * in).
+ */
+static void multires_reshape_calculate_delta(
+ MultiresPropagateData *data,
+ CCGElem **delta_grids_data)
+{
+ const int num_grids = data->num_grids;
+ /* At this point those custom data layers has updated data for the
+ * level we are propagating from.
+ */
+ const MDisps *mdisps = data->mdisps;
+ const GridPaintMask *grid_paint_mask = data->grid_paint_mask;
+ CCGKey *reshape_key = &data->reshape_level_key;
+ CCGKey *delta_level_key = &data->top_level_key;
+ /* Calculate delta. */
+ const int top_grid_size = data->top_grid_size;
+ const int reshape_grid_size = data->reshape_grid_size;
+ const int delta_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (reshape_grid_size - 1);
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ /*const*/ CCGElem *orig_grid = data->orig_grids_data[grid_index];
+ CCGElem *delta_grid = delta_grids_data[grid_index];
+ for (int y = 0; y < reshape_grid_size; y++) {
+ const int top_y = y * skip;
+ for (int x = 0; x < reshape_grid_size; x++) {
+ const int top_x = x * skip;
+ const int top_index = top_y * delta_grid_size + top_x;
+ sub_v3_v3v3(
+ CCG_grid_elem_co(
+ delta_level_key, delta_grid, top_x, top_y),
+ mdisps[grid_index].disps[top_index],
+ CCG_grid_elem_co(reshape_key, orig_grid, x, y));
+ if (delta_level_key->has_mask) {
+ const float old_mask_value = *CCG_grid_elem_mask(
+ reshape_key, orig_grid, x, y);
+ const float new_mask_value =
+ grid_paint_mask[grid_index].data[top_index];
+ *CCG_grid_elem_mask(
+ delta_level_key, delta_grid, top_x, top_y) =
+ new_mask_value - old_mask_value;
+ }
+ }
+ }
+ }
+}
+
+/* Makes it so delta is propagated onto all the higher levels, but is also
+ * that this delta is smoothed in a way that it does not cause artifacts on
+ * boundaries.
+ */
+
+typedef struct MultiresPropagateCornerData {
+ float coord_delta[3];
+ float mask_delta;
+} MultiresPropagateCornerData;
+
+BLI_INLINE void multires_reshape_propagate_init_patch_corners(
+ MultiresPropagateData *data,
+ CCGElem *delta_grid,
+ const int patch_x, const int patch_y,
+ MultiresPropagateCornerData r_corners[4])
+{
+ CCGKey *delta_level_key = &data->top_level_key;
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ const int x = patch_x * skip;
+ const int y = patch_y * skip;
+ /* Store coordinate deltas. */
+ copy_v3_v3(r_corners[0].coord_delta,
+ CCG_grid_elem_co(delta_level_key, delta_grid, x, y));
+ copy_v3_v3(r_corners[1].coord_delta,
+ CCG_grid_elem_co(delta_level_key, delta_grid, x + skip, y));
+ copy_v3_v3(r_corners[2].coord_delta,
+ CCG_grid_elem_co(delta_level_key, delta_grid, x, y + skip));
+ copy_v3_v3(r_corners[3].coord_delta,
+ CCG_grid_elem_co(delta_level_key, delta_grid,
+ x + skip, y + skip));
+ if (delta_level_key->has_mask) {
+ r_corners[0].mask_delta =
+ *CCG_grid_elem_mask(delta_level_key, delta_grid, x, y);
+ r_corners[1].mask_delta =
+ *CCG_grid_elem_mask(delta_level_key, delta_grid,
+ x + skip, y);
+ r_corners[2].mask_delta =
+ *CCG_grid_elem_mask(delta_level_key, delta_grid,
+ x, y + skip);
+ r_corners[3].mask_delta =
+ *CCG_grid_elem_mask(delta_level_key, delta_grid,
+ x + skip, y + skip);
+ }
+}
+
+BLI_INLINE void multires_reshape_propagate_interpolate_coord(
+ float delta[3],
+ const MultiresPropagateCornerData corners[4],
+ const float weights[4])
+{
+ interp_v3_v3v3v3v3(
+ delta,
+ corners[0].coord_delta, corners[1].coord_delta,
+ corners[2].coord_delta, corners[3].coord_delta,
+ weights);
+}
+
+BLI_INLINE float multires_reshape_propagate_interpolate_mask(
+ const MultiresPropagateCornerData corners[4],
+ const float weights[4])
+{
+ return corners[0].mask_delta * weights[0] +
+ corners[1].mask_delta * weights[1] +
+ corners[2].mask_delta * weights[2] +
+ corners[3].mask_delta * weights[3];
+}
+
+BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid_patch(
+ MultiresPropagateData *data,
+ CCGElem *delta_grid,
+ const int patch_x, const int patch_y)
+{
+ CCGKey *delta_level_key = &data->top_level_key;
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ const float skip_inv = 1.0f / (float)skip;
+ MultiresPropagateCornerData corners[4];
+ multires_reshape_propagate_init_patch_corners(
+ data, delta_grid, patch_x, patch_y, corners);
+ const int start_x = patch_x * skip;
+ const int start_y = patch_y * skip;
+ for (int y = 0; y <= skip; y++) {
+ const float v = (float)y * skip_inv;
+ const int final_y = start_y + y;
+ for (int x = 0; x <= skip; x++) {
+ const float u = (float)x * skip_inv;
+ const int final_x = start_x + x;
+ const float linear_weights[4] = {(1.0f - u) * (1.0f - v),
+ u * (1.0f - v),
+ (1.0f - u) * v,
+ u * v};
+ multires_reshape_propagate_interpolate_coord(
+ CCG_grid_elem_co(delta_level_key, delta_grid,
+ final_x, final_y),
+ corners,
+ linear_weights);
+ if (delta_level_key->has_mask) {
+ float *mask = CCG_grid_elem_mask(delta_level_key, delta_grid,
+ final_x, final_y);
+ *mask = multires_reshape_propagate_interpolate_mask(
+ corners, linear_weights);
+ }
+ }
+ }
+}
+
+BLI_INLINE void multires_reshape_propagate_and_smooth_delta_grid(
+ MultiresPropagateData *data,
+ CCGElem *delta_grid)
+{
+ const int orig_grid_size = data->reshape_grid_size;
+ for (int patch_y = 0; patch_y < orig_grid_size - 1; patch_y++) {
+ for (int patch_x = 0; patch_x < orig_grid_size - 1; patch_x++) {
+ multires_reshape_propagate_and_smooth_delta_grid_patch(
+ data, delta_grid, patch_x, patch_y);
+ }
+ }
+}
+
+/* Entry point to propagate+smooth. */
+static void multires_reshape_propagate_and_smooth_delta(
+ MultiresPropagateData *data,
+ CCGElem **delta_grids_data)
+{
+ const int num_grids = data->num_grids;
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *delta_grid = delta_grids_data[grid_index];
+ multires_reshape_propagate_and_smooth_delta_grid(data, delta_grid);
+ }
+}
+
+/* Apply smoothed deltas on the actual data layers. */
+static void multires_reshape_propagate_apply_delta(
+ MultiresPropagateData *data,
+ CCGElem **delta_grids_data)
+{
+ const int num_grids = data->num_grids;
+ /* At this point those custom data layers has updated data for the
+ * level we are propagating from.
+ */
+ MDisps *mdisps = data->mdisps;
+ GridPaintMask *grid_paint_mask = data->grid_paint_mask;
+ CCGKey *orig_key = &data->reshape_level_key;
+ CCGKey *delta_level_key = &data->top_level_key;
+ CCGElem **orig_grids_data = data->orig_grids_data;
+ const int orig_grid_size = data->reshape_grid_size;
+ const int top_grid_size = data->top_grid_size;
+ const int skip = (top_grid_size - 1) / (orig_grid_size - 1);
+ /* Restore grid values at the reshape level. Those values are to be changed
+ * to the accommodate for the smooth delta.
+ */
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *orig_grid = orig_grids_data[grid_index];
+ for (int y = 0; y < orig_grid_size; y++) {
+ const int top_y = y * skip;
+ for (int x = 0; x < orig_grid_size; x++) {
+ const int top_x = x * skip;
+ const int top_index = top_y * top_grid_size + top_x;
+ copy_v3_v3(mdisps[grid_index].disps[top_index],
+ CCG_grid_elem_co(orig_key, orig_grid, x, y));
+ if (grid_paint_mask != NULL) {
+ grid_paint_mask[grid_index].data[top_index] =
+ *CCG_grid_elem_mask(orig_key, orig_grid, x, y);
+ }
+ }
+ }
+ }
+ /* Add smoothed delta to all the levels. */
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ CCGElem *delta_grid = delta_grids_data[grid_index];
+ for (int y = 0; y < top_grid_size; y++) {
+ for (int x = 0; x < top_grid_size; x++) {
+ const int top_index = y * top_grid_size + x;
+ add_v3_v3(mdisps[grid_index].disps[top_index],
+ CCG_grid_elem_co(delta_level_key, delta_grid, x, y));
+ if (delta_level_key->has_mask) {
+ grid_paint_mask[grid_index].data[top_index] +=
+ *CCG_grid_elem_mask(
+ delta_level_key, delta_grid, x, y);
+ }
+ }
+ }
+ }
+}
+
+static void multires_reshape_propagate(MultiresPropagateData *data)
+{
+ if (data->reshape_level == data->top_level) {
+ return;
+ }
+ const int num_grids = data->num_grids;
+ /* Calculate delta made at the reshape level. */
+ CCGKey *delta_level_key = &data->top_level_key;
+ CCGElem **delta_grids_data = allocate_grids(delta_level_key, num_grids);
+ multires_reshape_calculate_delta(data, delta_grids_data);
+ /* Propagate deltas to the higher levels. */
+ multires_reshape_propagate_and_smooth_delta(data, delta_grids_data);
+ /* Finally, apply smoothed deltas. */
+ multires_reshape_propagate_apply_delta(data, delta_grids_data);
+ /* Cleanup. */
+ free_grids(delta_grids_data, num_grids);
+}
+
+static void multires_reshape_propagate_free(MultiresPropagateData *data)
+{
+ free_grids(data->orig_grids_data, data->num_grids);
+}
+
+/* =============================================================================
+ * Reshape from deformed vertex coordinates.
+ */
+
+typedef struct MultiresReshapeFromDeformedVertsContext {
+ MultiresReshapeContext reshape_ctx;
+ const float (*deformed_verts)[3];
+ int num_deformed_verts;
+} MultiresReshapeFromDeformedVertsContext;
+
+static bool multires_reshape_topology_info(
+ const SubdivForeachContext *foreach_context,
+ const int num_vertices,
+ const int UNUSED(num_edges),
+ const int UNUSED(num_loops),
+ const int UNUSED(num_polygons))
+{
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ if (num_vertices != ctx->num_deformed_verts) {
+ return false;
+ }
+ return true;
+}
+
+static void multires_reshape_vertex(
+ MultiresReshapeFromDeformedVertsContext *ctx,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ const float *final_P = ctx->deformed_verts[subdiv_vertex_index];
+ multires_reshape_vertex_from_final_data(
+ &ctx->reshape_ctx,
+ ptex_face_index, u, v,
+ coarse_poly_index,
+ coarse_corner,
+ final_P, 0.0f);
+}
+
+static void multires_reshape_vertex_inner(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ multires_reshape_vertex(
+ ctx,
+ ptex_face_index, u, v,
+ coarse_poly_index,
+ coarse_corner,
+ subdiv_vertex_index);
+}
+
+static void multires_reshape_vertex_every_corner(
+ const struct SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_vertex_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ multires_reshape_vertex(
+ ctx,
+ ptex_face_index, u, v,
+ coarse_poly_index,
+ coarse_corner,
+ subdiv_vertex_index);
+}
+
+static void multires_reshape_vertex_every_edge(
+ const struct SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_edge_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ MultiresReshapeFromDeformedVertsContext *ctx = foreach_context->user_data;
+ multires_reshape_vertex(
+ ctx,
+ ptex_face_index, u, v,
+ coarse_poly_index,
+ coarse_corner,
+ subdiv_vertex_index);
+}
+
+static Subdiv *multires_create_subdiv_for_reshape(
+ struct Depsgraph *depsgraph,
+ /*const*/ Object *object,
+ const MultiresModifierData *mmd)
+{
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, object);
+ Mesh *deformed_mesh = mesh_get_eval_deform(
+ depsgraph, scene_eval, object_eval, CD_MASK_BAREMESH);
+ SubdivSettings subdiv_settings;
+ BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
+ Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, deformed_mesh);
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, deformed_mesh)) {
+ BKE_subdiv_free(subdiv);
+ return NULL;
+ }
+ return subdiv;
+}
+
+static bool multires_reshape_from_vertcos(
+ struct Depsgraph *depsgraph,
+ Object *object,
+ const MultiresModifierData *mmd,
+ const float (*deformed_verts)[3],
+ const int num_deformed_verts,
+ const bool use_render_params)
+{
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Mesh *coarse_mesh = object->data;
+ MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
+ /* Make sure displacement grids are ready. */
+ multires_reshape_ensure_grids(coarse_mesh, mmd->totlvl);
+ /* Pick maximum between multires level and dispalcement level.
+ * This is because mesh can be used by objects with multires at different
+ * levels.
+ *
+ * TODO(sergey): At this point it should be possible to always use
+ * mdisps->level.
+ */
+ const int top_level = max_ii(mmd->totlvl, mdisps->level);
+ /* Construct context. */
+ MultiresReshapeFromDeformedVertsContext reshape_deformed_verts_ctx = {
+ .reshape_ctx = {
+ .coarse_mesh = coarse_mesh,
+ .mdisps = mdisps,
+ .grid_paint_mask = NULL,
+ .top_grid_size = BKE_subdiv_grid_size_from_level(top_level),
+ .top_level = top_level,
+ },
+ .deformed_verts = deformed_verts,
+ .num_deformed_verts = num_deformed_verts,
+ };
+ SubdivForeachContext foreach_context = {
+ .topology_info = multires_reshape_topology_info,
+ .vertex_inner = multires_reshape_vertex_inner,
+ .vertex_every_edge = multires_reshape_vertex_every_edge,
+ .vertex_every_corner = multires_reshape_vertex_every_corner,
+ .user_data = &reshape_deformed_verts_ctx,
+ };
+ /* Initialize subdivision surface. */
+ Subdiv *subdiv = multires_create_subdiv_for_reshape(depsgraph, object, mmd);
+ if (subdiv == NULL) {
+ return false;
+ }
+ reshape_deformed_verts_ctx.reshape_ctx.subdiv = subdiv;
+ /* Initialize mesh rasterization settings. */
+ SubdivToMeshSettings mesh_settings;
+ BKE_multires_subdiv_mesh_settings_init(
+ &mesh_settings, scene_eval, object, mmd, use_render_params, true);
+ /* Initialize propagation to higher levels. */
+ MultiresPropagateData propagate_data;
+ multires_reshape_propagate_prepare_from_mmd(
+ &propagate_data, depsgraph, object, mmd, top_level, use_render_params);
+ /* Run all the callbacks. */
+ BKE_subdiv_foreach_subdiv_geometry(
+ subdiv,
+ &foreach_context,
+ &mesh_settings,
+ coarse_mesh);
+ BKE_subdiv_free(subdiv);
+ /* Update higher levels if needed. */
+ multires_reshape_propagate(&propagate_data);
+ multires_reshape_propagate_free(&propagate_data);
+ return true;
+}
+
+/* =============================================================================
+ * Reshape from object.
+ */
+
+/* Returns truth on success, false otherwise.
+ *
+ * This function might fail in cases like source and destination not having
+ * matched amount of vertices.
+ */
+bool multiresModifier_reshapeFromObject(
+ struct Depsgraph *depsgraph,
+ MultiresModifierData *mmd,
+ Object *dst,
+ Object *src)
+{
+ /* Would be cool to support this eventually, but it is very tricky to match
+ * vertices order even for meshes, when mixing meshes and other objects it's
+ * even more tricky.
+ */
+ if (src->type != OB_MESH) {
+ return false;
+ }
+ MultiresModifierData reshape_mmd;
+ multires_reshape_init_mmd(&reshape_mmd, mmd);
+ /* Get evaluated vertices locations to reshape to. */
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *src_eval = DEG_get_evaluated_object(depsgraph, src);
+ Mesh *src_mesh_eval = mesh_get_eval_final(
+ depsgraph, scene_eval, src_eval, CD_MASK_BAREMESH);
+ int num_deformed_verts;
+ float (*deformed_verts)[3] = BKE_mesh_vertexCos_get(
+ src_mesh_eval, &num_deformed_verts);
+ bool result = multires_reshape_from_vertcos(
+ depsgraph,
+ dst,
+ &reshape_mmd,
+ deformed_verts,
+ num_deformed_verts,
+ false);
+ MEM_freeN(deformed_verts);
+ return result;
+}
+
+/* =============================================================================
+ * Reshape from modifier.
+ */
+
+bool multiresModifier_reshapeFromDeformModifier(
+ struct Depsgraph *depsgraph,
+ MultiresModifierData *mmd,
+ Object *object,
+ ModifierData *md)
+{
+ MultiresModifierData highest_mmd;
+ /* It is possible that the current subdivision level of multires is lower
+ * that it's maximum possible one (i.e., viewport is set to a lower level
+ * for the performance purposes). But even then, we want all the multires
+ * levels to be reshaped. Most accurate way to do so is to ignore all
+ * simplifications and calculate deformation modifier for the highest
+ * possible multires level.
+ * Alternative would be propagate displacement from current level to a
+ * higher ones, but that is likely to cause artifacts.
+ */
+ multires_reshape_init_mmd_top_level(&highest_mmd, mmd);
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ /* Perform sanity checks and early output. */
+ if (multires_get_level(
+ scene_eval, object, &highest_mmd, false, true) == 0)
+ {
+ return false;
+ }
+ /* Create mesh for the multires, ignoring any further modifiers (leading
+ * deformation modifiers will be applied though).
+ */
+ Mesh *multires_mesh = BKE_multires_create_mesh(
+ depsgraph, scene_eval, &highest_mmd, object);
+ int num_deformed_verts;
+ float (*deformed_verts)[3] = BKE_mesh_vertexCos_get(
+ multires_mesh, &num_deformed_verts);
+ /* Apply deformation modifier on the multires, */
+ const ModifierEvalContext modifier_ctx = {
+ .depsgraph = depsgraph,
+ .object = object,
+ .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY};
+ modwrap_deformVerts(
+ md, &modifier_ctx, multires_mesh, deformed_verts,
+ multires_mesh->totvert);
+ BKE_id_free(NULL, multires_mesh);
+ /* Reshaping */
+ bool result = multires_reshape_from_vertcos(
+ depsgraph,
+ object,
+ &highest_mmd,
+ deformed_verts,
+ num_deformed_verts,
+ false);
+ /* Cleanup */
+ MEM_freeN(deformed_verts);
+ return result;
+}
+
+/* =============================================================================
+ * Reshape from grids.
+ */
+
+typedef struct ReshapeFromCCGTaskData {
+ MultiresReshapeContext reshape_ctx;
+ int *face_ptex_offset;
+ const CCGKey *key;
+ /*const*/ CCGElem **grids;
+} ReshapeFromCCGTaskData;
+
+static void reshape_from_ccg_regular_face(ReshapeFromCCGTaskData *data,
+ const MPoly *coarse_poly)
+{
+ const CCGKey *key = data->key;
+ /*const*/ CCGElem **grids = data->grids;
+ const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int key_grid_size = key->grid_size;
+ const int key_grid_size_1 = key_grid_size - 1;
+ const int resolution = 2 * key_grid_size - 1;
+ const float resolution_1_inv = 1.0f / (float)(resolution - 1);
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_face_index = data->face_ptex_offset[coarse_poly_index];
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * resolution_1_inv;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * resolution_1_inv;
+ float corner_u, corner_v;
+ float grid_u, grid_v;
+ const int face_corner = BKE_subdiv_rotate_quad_to_corner(
+ u, v, &corner_u, &corner_v);
+ BKE_subdiv_ptex_face_uv_to_grid_uv(
+ corner_u, corner_v, &grid_u, &grid_v);
+ /*const*/ CCGElem *grid =
+ grids[coarse_poly->loopstart + face_corner];
+ /*const*/ CCGElem *grid_element = CCG_grid_elem(
+ key,
+ grid,
+ key_grid_size_1 * grid_u,
+ key_grid_size_1 * grid_v);
+ const float *final_P = CCG_elem_co(key, grid_element);
+ float final_mask = 0.0f;
+ if (key->has_mask) {
+ final_mask = *CCG_elem_mask(key, grid_element);
+ }
+ multires_reshape_vertex_from_final_data(
+ &data->reshape_ctx,
+ ptex_face_index,
+ u, v,
+ coarse_poly_index,
+ 0,
+ final_P, final_mask);
+ }
+ }
+}
+
+static void reshape_from_ccg_special_face(ReshapeFromCCGTaskData *data,
+ const MPoly *coarse_poly)
+{
+ const CCGKey *key = data->key;
+ /*const*/ CCGElem **grids = data->grids;
+ const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int key_grid_size = key->grid_size;
+ const int key_grid_size_1 = key_grid_size - 1;
+ const int resolution = key_grid_size;
+ const float resolution_1_inv = 1.0f / (float)(resolution - 1);
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_face_index = data->face_ptex_offset[coarse_poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * resolution_1_inv;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * resolution_1_inv;
+ float grid_u, grid_v;
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, &grid_u, &grid_v);
+ /*const*/ CCGElem *grid =
+ grids[coarse_poly->loopstart + corner];
+ /*const*/ CCGElem *grid_element = CCG_grid_elem(
+ key,
+ grid,
+ key_grid_size_1 * grid_u,
+ key_grid_size_1 * grid_v);
+ const float *final_P = CCG_elem_co(key, grid_element);
+ float final_mask = 0.0f;
+ if (key->has_mask) {
+ final_mask = *CCG_elem_mask(key, grid_element);
+ }
+ multires_reshape_vertex_from_final_data(
+ &data->reshape_ctx,
+ ptex_face_index + corner,
+ u, v,
+ coarse_poly_index,
+ corner,
+ final_P, final_mask);
+ }
+ }
+ }
+}
+
+static void reshape_from_ccg_task(
+ void *__restrict userdata,
+ const int coarse_poly_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ ReshapeFromCCGTaskData *data = userdata;
+ const Mesh *coarse_mesh = data->reshape_ctx.coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ if (coarse_poly->totloop == 4) {
+ reshape_from_ccg_regular_face(data, coarse_poly);
+ }
+ else {
+ reshape_from_ccg_special_face(data, coarse_poly);
+ }
+}
+
+bool multiresModifier_reshapeFromCCG(
+ const int tot_level,
+ Mesh *coarse_mesh,
+ SubdivCCG *subdiv_ccg)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ /* Sanity checks. */
+ if (coarse_mesh->totloop != subdiv_ccg->num_grids) {
+ /* Grids are supposed to eb created for each face-cornder (aka loop). */
+ return false;
+ }
+ MDisps *mdisps = CustomData_get_layer(&coarse_mesh->ldata, CD_MDISPS);
+ GridPaintMask *grid_paint_mask =
+ CustomData_get_layer(&coarse_mesh->ldata, CD_GRID_PAINT_MASK);
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ /* Make sure displacement grids are ready. */
+ multires_reshape_ensure_grids(coarse_mesh, tot_level);
+ /* Pick maximum between multires level and dispalcement level.
+ * This is because mesh can be used by objects with multires at different
+ * levels.
+ *
+ * TODO(sergey): At this point it should be possible to always use
+ * mdisps->level.
+ */
+ const int top_level = max_ii(tot_level, mdisps->level);
+ /* Construct context. */
+ ReshapeFromCCGTaskData data = {
+ .reshape_ctx = {
+ .subdiv = subdiv,
+ .coarse_mesh = coarse_mesh,
+ .mdisps = mdisps,
+ .grid_paint_mask = grid_paint_mask,
+ .top_grid_size = BKE_subdiv_grid_size_from_level(top_level),
+ .top_level = top_level},
+ .face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv),
+ .key = &key,
+ .grids = subdiv_ccg->grids};
+ /* Initialize propagation to higher levels. */
+ MultiresPropagateData propagate_data;
+ multires_reshape_propagate_prepare(
+ &propagate_data, coarse_mesh, key.level, top_level);
+ /* Threaded grids iteration. */
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ BLI_task_parallel_range(0, coarse_mesh->totpoly,
+ &data,
+ reshape_from_ccg_task,
+ &parallel_range_settings);
+ /* Update higher levels if needed. */
+ multires_reshape_propagate(&propagate_data);
+ multires_reshape_propagate_free(&propagate_data);
+ return true;
+}
diff --git a/source/blender/blenkernel/intern/multires_subdiv.c b/source/blender/blenkernel/intern/multires_subdiv.c
new file mode 100644
index 00000000000..e0b316d49de
--- /dev/null
+++ b/source/blender/blenkernel/intern/multires_subdiv.c
@@ -0,0 +1,67 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/multires_subdiv.c
+ * \ingroup bke
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_mesh.h"
+
+void BKE_multires_subdiv_settings_init(
+ SubdivSettings *settings,
+ const MultiresModifierData *mmd)
+{
+ settings->is_simple = (mmd->simple != 0);
+ settings->is_adaptive = !settings->is_simple;
+ settings->level = mmd->quality;
+ settings->vtx_boundary_interpolation = SUBDIV_VTX_BOUNDARY_EDGE_ONLY;
+ settings->fvar_linear_interpolation =
+ BKE_subdiv_fvar_interpolation_from_uv_smooth(mmd->uv_smooth);
+}
+
+void BKE_multires_subdiv_mesh_settings_init(
+ SubdivToMeshSettings *mesh_settings,
+ const Scene *scene,
+ const Object *object,
+ const MultiresModifierData *mmd,
+ const bool use_render_params,
+ const bool ignore_simplify)
+{
+ const int level = multires_get_level(
+ scene, object, mmd, use_render_params, ignore_simplify);
+ mesh_settings->resolution = (1 << level) + 1;
+}
diff --git a/source/blender/blenkernel/intern/navmesh_conversion.c b/source/blender/blenkernel/intern/navmesh_conversion.c
deleted file mode 100644
index 35bcca52f63..00000000000
--- a/source/blender/blenkernel/intern/navmesh_conversion.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/navmesh_conversion.c
- * \ingroup bke
- */
-
-#include <math.h>
-#include <stdlib.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_meshdata_types.h"
-
-#include "BLI_utildefines.h"
-#include "BLI_math.h"
-#include "BLI_sort.h"
-
-#include "BKE_navmesh_conversion.h"
-#include "BKE_cdderivedmesh.h"
-
-#include "recast-capi.h"
-
-BLI_INLINE float area2(const float *a, const float *b, const float *c)
-{
- return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]);
-}
-
-BLI_INLINE int left(const float *a, const float *b, const float *c)
-{
- return area2(a, b, c) < 0;
-}
-
-int polyNumVerts(const unsigned short *p, const int vertsPerPoly)
-{
- int i, nv = 0;
- for (i = 0; i < vertsPerPoly; i++) {
- if (p[i] == 0xffff)
- break;
- nv++;
- }
- return nv;
-}
-
-int polyIsConvex(const unsigned short *p, const int vertsPerPoly, const float *verts)
-{
- int j, nv = polyNumVerts(p, vertsPerPoly);
- if (nv < 3)
- return 0;
- for (j = 0; j < nv; j++) {
- const float *v = &verts[3 * p[j]];
- const float *v_next = &verts[3 * p[(j + 1) % nv]];
- const float *v_prev = &verts[3 * p[(nv + j - 1) % nv]];
- if (!left(v_prev, v, v_next))
- return 0;
-
- }
- return 1;
-}
-
-/* XXX, could replace with #dist_to_line_segment_v3(), or add a squared version */
-float distPointToSegmentSq(const float point[3], const float a[3], const float b[3])
-{
- float abx[3], dx[3];
- float d, t;
-
- sub_v3_v3v3(abx, b, a);
- sub_v3_v3v3(dx, point, a);
-
- d = abx[0] * abx[0] + abx[2] * abx[2];
- t = abx[0] * dx[0] + abx[2] * dx[2];
-
- if (d > 0.0f)
- t /= d;
- if (t < 0.0f)
- t = 0.0f;
- else if (t > 1.0f)
- t = 1.0f;
- dx[0] = a[0] + t * abx[0] - point[0];
- dx[2] = a[2] + t * abx[2] - point[2];
-
- return dx[0] * dx[0] + dx[2] * dx[2];
-}
-
-int buildRawVertIndicesData(DerivedMesh *dm, int *nverts_r, float **verts_r,
- int *ntris_r, unsigned short **tris_r, int **trisToFacesMap_r,
- int **recastData)
-{
- int vi, fi, triIdx;
- int nverts, ntris;
- int *trisToFacesMap;
- float *verts;
- unsigned short *tris, *tri;
- int nfaces;
- MFace *faces;
-
- nverts = dm->getNumVerts(dm);
- if (nverts >= 0xffff) {
- printf("Converting navmesh: Error! Too many vertices. Max number of vertices %d\n", 0xffff);
- return 0;
- }
- if (nverts == 0) {
- printf("Converting navmesh: Error! There are no vertices!\n");
- return 0;
- }
-
- verts = MEM_mallocN(sizeof(float[3]) * nverts, "buildRawVertIndicesData verts");
- dm->getVertCos(dm, (float(*)[3])verts);
-
- /* flip coordinates */
- for (vi = 0; vi < nverts; vi++) {
- SWAP(float, verts[3 * vi + 1], verts[3 * vi + 2]);
- }
-
- /* calculate number of tris */
- dm->recalcTessellation(dm);
- nfaces = dm->getNumTessFaces(dm);
- if (nfaces == 0) {
- printf("Converting navmesh: Error! There are %i vertices, but no faces!\n", nverts);
- return 0;
- }
-
- faces = dm->getTessFaceArray(dm);
- ntris = nfaces;
- for (fi = 0; fi < nfaces; fi++) {
- MFace *face = &faces[fi];
- if (face->v4)
- ntris++;
- }
-
- /* copy and transform to triangles (reorder on the run) */
- trisToFacesMap = MEM_callocN(sizeof(int) * ntris, "buildRawVertIndicesData trisToFacesMap");
- tris = MEM_callocN(sizeof(unsigned short) * 3 * ntris, "buildRawVertIndicesData tris");
- tri = tris;
- triIdx = 0;
- for (fi = 0; fi < nfaces; fi++) {
- MFace *face = &faces[fi];
- tri[3 * triIdx + 0] = (unsigned short) face->v1;
- tri[3 * triIdx + 1] = (unsigned short) face->v3;
- tri[3 * triIdx + 2] = (unsigned short) face->v2;
- trisToFacesMap[triIdx++] = fi;
- if (face->v4) {
- tri[3 * triIdx + 0] = (unsigned short) face->v1;
- tri[3 * triIdx + 1] = (unsigned short) face->v4;
- tri[3 * triIdx + 2] = (unsigned short) face->v3;
- trisToFacesMap[triIdx++] = fi;
- }
- }
-
- /* carefully, recast data is just reference to data in derived mesh */
- *recastData = (int *)CustomData_get_layer(&dm->polyData, CD_RECAST);
-
- *nverts_r = nverts;
- *verts_r = verts;
- *ntris_r = ntris;
- *tris_r = tris;
- *trisToFacesMap_r = trisToFacesMap;
-
- return 1;
-}
-
-int buildPolygonsByDetailedMeshes(const int vertsPerPoly, const int npolys,
- unsigned short *polys, const unsigned short *dmeshes,
- const float *verts, const unsigned short *dtris,
- const int *dtrisToPolysMap)
-{
- int polyidx;
- int capacity = vertsPerPoly;
- unsigned short *newPoly = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPoly");
- memset(newPoly, 0xff, sizeof(unsigned short) * capacity);
-
- for (polyidx = 0; polyidx < npolys; polyidx++) {
- size_t i;
- int j, k;
- int nv = 0;
- /* search border */
- int tri, btri = -1;
- int edge, bedge = -1;
- int dtrisNum = dmeshes[polyidx * 4 + 3];
- int dtrisBase = dmeshes[polyidx * 4 + 2];
- unsigned char *traversedTris = MEM_callocN(sizeof(unsigned char) * dtrisNum, "buildPolygonsByDetailedMeshes traversedTris");
- unsigned short *adjustedPoly;
- int adjustedNv;
- int allBorderTraversed;
-
- for (j = 0; j < dtrisNum && btri == -1; j++) {
- int curpolytri = dtrisBase + j;
- for (k = 0; k < 3; k++) {
- unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k];
- if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
- btri = curpolytri;
- bedge = k;
- break;
- }
- }
- }
- if (btri == -1 || bedge == -1) {
- /* can't find triangle with border edge */
- MEM_freeN(traversedTris);
- MEM_freeN(newPoly);
-
- return 0;
- }
-
- newPoly[nv++] = dtris[btri * 3 * 2 + bedge];
- tri = btri;
- edge = (bedge + 1) % 3;
- traversedTris[tri - dtrisBase] = 1;
- while (tri != btri || edge != bedge) {
- int neighbortri = dtris[tri * 3 * 2 + 3 + edge];
- if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
- if (nv == capacity) {
- unsigned short *newPolyBig;
- capacity += vertsPerPoly;
- newPolyBig = MEM_callocN(sizeof(unsigned short) * capacity, "buildPolygonsByDetailedMeshes newPolyBig");
- memset(newPolyBig, 0xff, sizeof(unsigned short) * capacity);
- memcpy(newPolyBig, newPoly, sizeof(unsigned short) * nv);
- MEM_freeN(newPoly);
- newPoly = newPolyBig;
- }
- newPoly[nv++] = dtris[tri * 3 * 2 + edge];
- /* move to next edge */
- edge = (edge + 1) % 3;
- }
- else {
- /* move to next tri */
- int twinedge = -1;
- for (k = 0; k < 3; k++) {
- if (dtris[neighbortri * 3 * 2 + 3 + k] == tri) {
- twinedge = k;
- break;
- }
- }
- if (twinedge == -1) {
- printf("Converting navmesh: Error! Can't find neighbor edge - invalid adjacency info\n");
- MEM_freeN(traversedTris);
- goto returnLabel;
- }
- tri = neighbortri;
- edge = (twinedge + 1) % 3;
- traversedTris[tri - dtrisBase] = 1;
- }
- }
-
- adjustedPoly = MEM_callocN(sizeof(unsigned short) * nv, "buildPolygonsByDetailedMeshes adjustedPoly");
- adjustedNv = 0;
- for (i = 0; i < nv; i++) {
- unsigned short prev = newPoly[(nv + i - 1) % nv];
- unsigned short cur = newPoly[i];
- unsigned short next = newPoly[(i + 1) % nv];
- float distSq = distPointToSegmentSq(&verts[3 * cur], &verts[3 * prev], &verts[3 * next]);
- static const float tolerance = 0.001f;
- if (distSq > tolerance)
- adjustedPoly[adjustedNv++] = cur;
- }
- memcpy(newPoly, adjustedPoly, adjustedNv * sizeof(unsigned short));
- MEM_freeN(adjustedPoly);
- nv = adjustedNv;
-
- allBorderTraversed = 1;
- for (i = 0; i < dtrisNum; i++) {
- if (traversedTris[i] == 0) {
- /* check whether it has border edges */
- int curpolytri = dtrisBase + i;
- for (k = 0; k < 3; k++) {
- unsigned short neighbortri = dtris[curpolytri * 3 * 2 + 3 + k];
- if (neighbortri == 0xffff || dtrisToPolysMap[neighbortri] != polyidx + 1) {
- allBorderTraversed = 0;
- break;
- }
- }
- }
- }
-
- if (nv <= vertsPerPoly && allBorderTraversed) {
- for (i = 0; i < nv; i++) {
- polys[polyidx * vertsPerPoly * 2 + i] = newPoly[i];
- }
- }
-
- MEM_freeN(traversedTris);
- }
-
-returnLabel:
- MEM_freeN(newPoly);
-
- return 1;
-}
-
-struct SortContext {
- const int *recastData;
- const int *trisToFacesMap;
-};
-
-static int compareByData(const void *a, const void *b, void *ctx)
-{
- return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)a]] -
- ((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)b]]);
-}
-
-int buildNavMeshData(const int nverts, const float *verts,
- const int ntris, const unsigned short *tris,
- const int *recastData, const int *trisToFacesMap,
- int *ndtris_r, unsigned short **dtris_r,
- int *npolys_r, unsigned short **dmeshes_r, unsigned short **polys_r,
- int *vertsPerPoly_r, int **dtrisToPolysMap_r, int **dtrisToTrisMap_r)
-
-{
- int *trisMapping;
- int i;
- struct SortContext context;
- int validTriStart, prevPolyIdx, curPolyIdx, newPolyIdx, prevpolyidx;
- unsigned short *dmesh;
-
- int ndtris, npolys, vertsPerPoly;
- unsigned short *dtris, *dmeshes, *polys;
- int *dtrisToPolysMap, *dtrisToTrisMap;
-
- if (!recastData) {
- printf("Converting navmesh: Error! Can't find recast custom data\n");
- return 0;
- }
-
- trisMapping = MEM_callocN(sizeof(int) * ntris, "buildNavMeshData trisMapping");
-
- /* sort the triangles by polygon idx */
- for (i = 0; i < ntris; i++)
- trisMapping[i] = i;
- context.recastData = recastData;
- context.trisToFacesMap = trisToFacesMap;
- BLI_qsort_r(trisMapping, ntris, sizeof(int), compareByData, &context);
-
- /* search first valid triangle - triangle of convex polygon */
- validTriStart = -1;
- for (i = 0; i < ntris; i++) {
- if (recastData[trisToFacesMap[trisMapping[i]]] > 0) {
- validTriStart = i;
- break;
- }
- }
-
- if (validTriStart < 0) {
- printf("Converting navmesh: Error! No valid polygons in mesh\n");
- MEM_freeN(trisMapping);
- return 0;
- }
-
- ndtris = ntris - validTriStart;
- /* fill dtris to faces mapping */
- dtrisToTrisMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToTrisMap");
- memcpy(dtrisToTrisMap, &trisMapping[validTriStart], ndtris * sizeof(int));
- MEM_freeN(trisMapping);
-
- /* create detailed mesh triangles - copy only valid triangles
- * and reserve memory for adjacency info */
- dtris = MEM_callocN(sizeof(unsigned short) * 3 * 2 * ndtris, "buildNavMeshData dtris");
- memset(dtris, 0xff, sizeof(unsigned short) * 3 * 2 * ndtris);
- for (i = 0; i < ndtris; i++) {
- memcpy(dtris + 3 * 2 * i, tris + 3 * dtrisToTrisMap[i], sizeof(unsigned short) * 3);
- }
-
- /* create new recast data corresponded to dtris and renumber for continuous indices */
- prevPolyIdx = -1;
- newPolyIdx = 0;
- dtrisToPolysMap = MEM_callocN(sizeof(int) * ndtris, "buildNavMeshData dtrisToPolysMap");
- for (i = 0; i < ndtris; i++) {
- curPolyIdx = recastData[trisToFacesMap[dtrisToTrisMap[i]]];
- if (curPolyIdx != prevPolyIdx) {
- newPolyIdx++;
- prevPolyIdx = curPolyIdx;
- }
- dtrisToPolysMap[i] = newPolyIdx;
- }
-
-
- /* build adjacency info for detailed mesh triangles */
- if (!recast_buildMeshAdjacency(dtris, ndtris, nverts, 3)) {
- printf("Converting navmesh: Error! Unable to build mesh adjacency information\n");
- MEM_freeN(trisMapping);
- MEM_freeN(dtrisToPolysMap);
- return 0;
- }
-
- /* create detailed mesh description for each navigation polygon */
- npolys = dtrisToPolysMap[ndtris - 1];
- dmeshes = MEM_callocN(sizeof(unsigned short) * npolys * 4, "buildNavMeshData dmeshes");
- memset(dmeshes, 0, npolys * 4 * sizeof(unsigned short));
- dmesh = NULL;
- prevpolyidx = 0;
- for (i = 0; i < ndtris; i++) {
- int curpolyidx = dtrisToPolysMap[i];
- if (curpolyidx != prevpolyidx) {
- if (curpolyidx != prevpolyidx + 1) {
- printf("Converting navmesh: Error! Wrong order of detailed mesh faces\n");
- goto fail;
- }
- dmesh = dmesh == NULL ? dmeshes : dmesh + 4;
- dmesh[2] = (unsigned short)i; /* tbase */
- dmesh[3] = 0; /* tnum */
- prevpolyidx = curpolyidx;
- }
- dmesh[3]++;
- }
-
- /* create navigation polygons */
- vertsPerPoly = 6;
- polys = MEM_callocN(sizeof(unsigned short) * npolys * vertsPerPoly * 2, "buildNavMeshData polys");
- memset(polys, 0xff, sizeof(unsigned short) * vertsPerPoly * 2 * npolys);
-
- if (!buildPolygonsByDetailedMeshes(vertsPerPoly, npolys, polys, dmeshes, verts, dtris, dtrisToPolysMap)) {
- printf("Converting navmesh: Error! Unable to build polygons from detailed mesh\n");
- goto fail;
- }
-
- *ndtris_r = ndtris;
- *npolys_r = npolys;
- *vertsPerPoly_r = vertsPerPoly;
- *dtris_r = dtris;
- *dmeshes_r = dmeshes;
- *polys_r = polys;
- *dtrisToPolysMap_r = dtrisToPolysMap;
- *dtrisToTrisMap_r = dtrisToTrisMap;
-
- return 1;
-
-fail:
- MEM_freeN(dmeshes);
- MEM_freeN(dtrisToPolysMap);
- MEM_freeN(dtrisToTrisMap);
- return 0;
-}
-
-
-int buildNavMeshDataByDerivedMesh(DerivedMesh *dm, int *vertsPerPoly,
- int *nverts, float **verts,
- int *ndtris, unsigned short **dtris,
- int *npolys, unsigned short **dmeshes,
- unsigned short **polys, int **dtrisToPolysMap,
- int **dtrisToTrisMap, int **trisToFacesMap)
-{
- int res;
- int ntris = 0, *recastData = NULL;
- unsigned short *tris = NULL;
-
- res = buildRawVertIndicesData(dm, nverts, verts, &ntris, &tris, trisToFacesMap, &recastData);
- if (!res) {
- printf("Converting navmesh: Error! Can't get raw vertices and indices from mesh\n");
- goto exit;
- }
-
- res = buildNavMeshData(*nverts, *verts, ntris, tris, recastData, *trisToFacesMap,
- ndtris, dtris, npolys, dmeshes, polys, vertsPerPoly,
- dtrisToPolysMap, dtrisToTrisMap);
- if (!res) {
- printf("Converting navmesh: Error! Can't build navmesh data from mesh\n");
- goto exit;
- }
-
-exit:
- if (tris)
- MEM_freeN(tris);
-
- return res;
-}
-
-int polyFindVertex(const unsigned short *p, const int vertsPerPoly, unsigned short vertexIdx)
-{
- int i, res = -1;
- for (i = 0; i < vertsPerPoly; i++) {
- if (p[i] == 0xffff)
- break;
- if (p[i] == vertexIdx) {
- res = i;
- break;
- }
- }
- return res;
-}
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 75dd0416e52..192e6b5e56e 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -60,7 +60,7 @@
#include "BKE_nla.h"
#ifdef WITH_AUDASPACE
-# include AUD_SPECIAL_H
+# include <AUD_Special.h>
#endif
#include "RNA_access.h"
@@ -76,7 +76,7 @@
/* Remove the given NLA strip from the NLA track it occupies, free the strip's data,
* and the strip itself.
*/
-void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip)
+void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip, bool do_id_user)
{
NlaStrip *cs, *csn;
@@ -87,12 +87,13 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip)
/* free child-strips */
for (cs = strip->strips.first; cs; cs = csn) {
csn = cs->next;
- BKE_nlastrip_free(&strip->strips, cs);
+ BKE_nlastrip_free(&strip->strips, cs, do_id_user);
}
/* remove reference to action */
- if (strip->act)
+ if (strip->act != NULL && do_id_user) {
id_us_min(&strip->act->id);
+ }
/* free remapping info */
//if (strip->remap)
@@ -114,7 +115,7 @@ void BKE_nlastrip_free(ListBase *strips, NlaStrip *strip)
/* Remove the given NLA track from the set of NLA tracks, free the track's data,
* and the track itself.
*/
-void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt)
+void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt, bool do_id_user)
{
NlaStrip *strip, *stripn;
@@ -125,7 +126,7 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt)
/* free strips */
for (strip = nlt->strips.first; strip; strip = stripn) {
stripn = strip->next;
- BKE_nlastrip_free(&nlt->strips, strip);
+ BKE_nlastrip_free(&nlt->strips, strip, do_id_user);
}
/* free NLA track itself now */
@@ -138,7 +139,7 @@ void BKE_nlatrack_free(ListBase *tracks, NlaTrack *nlt)
/* Free the elements of type NLA Tracks provided in the given list, but do not free
* the list itself since that is not free-standing
*/
-void BKE_nla_tracks_free(ListBase *tracks)
+void BKE_nla_tracks_free(ListBase *tracks, bool do_id_user)
{
NlaTrack *nlt, *nltn;
@@ -149,7 +150,7 @@ void BKE_nla_tracks_free(ListBase *tracks)
/* free tracks one by one */
for (nlt = tracks->first; nlt; nlt = nltn) {
nltn = nlt->next;
- BKE_nlatrack_free(tracks, nlt);
+ BKE_nlatrack_free(tracks, nlt, do_id_user);
}
/* clear the list's pointers to be safe */
@@ -162,12 +163,15 @@ void BKE_nla_tracks_free(ListBase *tracks)
* Copy NLA strip
*
* \param use_same_action When true, the existing action is used (instead of being duplicated)
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
*/
-NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_action)
+NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_action, const int flag)
{
NlaStrip *strip_d;
NlaStrip *cs, *cs_d;
+ const bool do_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+
/* sanity check */
if (strip == NULL)
return NULL;
@@ -179,12 +183,14 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_ac
/* handle action */
if (strip_d->act) {
if (use_same_action) {
- /* increase user-count of action */
- id_us_plus(&strip_d->act->id);
+ if (do_id_user) {
+ /* increase user-count of action */
+ id_us_plus(&strip_d->act->id);
+ }
}
else {
/* use a copy of the action instead (user count shouldn't have changed yet) */
- strip_d->act = BKE_action_copy(bmain, strip_d->act);
+ BKE_id_copy_ex(bmain, &strip_d->act->id, (ID **)&strip_d->act, flag, false);
}
}
@@ -196,7 +202,7 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_ac
BLI_listbase_clear(&strip_d->strips);
for (cs = strip->strips.first; cs; cs = cs->next) {
- cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action);
+ cs_d = BKE_nlastrip_copy(bmain, cs, use_same_action, flag);
BLI_addtail(&strip_d->strips, cs_d);
}
@@ -204,8 +210,11 @@ NlaStrip *BKE_nlastrip_copy(Main *bmain, NlaStrip *strip, const bool use_same_ac
return strip_d;
}
-/* Copy NLA Track */
-NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_actions)
+/**
+ * Copy a single NLA Track.
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
+ */
+NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_actions, const int flag)
{
NlaStrip *strip, *strip_d;
NlaTrack *nlt_d;
@@ -222,7 +231,7 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_acti
BLI_listbase_clear(&nlt_d->strips);
for (strip = nlt->strips.first; strip; strip = strip->next) {
- strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions);
+ strip_d = BKE_nlastrip_copy(bmain, strip, use_same_actions, flag);
BLI_addtail(&nlt_d->strips, strip_d);
}
@@ -230,8 +239,11 @@ NlaTrack *BKE_nlatrack_copy(Main *bmain, NlaTrack *nlt, const bool use_same_acti
return nlt_d;
}
-/* Copy all NLA data */
-void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src)
+/**
+ * Copy all NLA data.
+ * \param flag Control ID pointers management, see LIB_ID_CREATE_.../LIB_ID_COPY_... flags in BKE_library.h
+ */
+void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src, const int flag)
{
NlaTrack *nlt, *nlt_d;
@@ -246,7 +258,7 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, ListBase *src)
for (nlt = src->first; nlt; nlt = nlt->next) {
/* make a copy, and add the copy to the destination list */
// XXX: we need to fix this sometime
- nlt_d = BKE_nlatrack_copy(bmain, nlt, true);
+ nlt_d = BKE_nlatrack_copy(bmain, nlt, true, flag);
BLI_addtail(dst, nlt_d);
}
}
@@ -752,7 +764,7 @@ void BKE_nlastrips_clear_metastrip(ListBase *strips, NlaStrip *strip)
}
/* free the meta-strip now */
- BKE_nlastrip_free(strips, strip);
+ BKE_nlastrip_free(strips, strip, true);
}
/* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
@@ -2013,30 +2025,3 @@ void BKE_nla_tweakmode_exit(AnimData *adt)
adt->actstrip = NULL;
adt->flag &= ~ADT_NLA_EDIT_ON;
}
-
-/* Baking Tools ------------------------------------------- */
-
-static void UNUSED_FUNCTION(BKE_nla_bake) (Scene *scene, ID *UNUSED(id), AnimData *adt, int UNUSED(flag))
-{
-
- /* verify that data is valid
- * 1) Scene and AnimData must be provided
- * 2) there must be tracks to merge...
- */
- if (ELEM(NULL, scene, adt, adt->nla_tracks.first))
- return;
-
- /* if animdata currently has an action, 'push down' this onto the stack first */
- if (adt->action)
- BKE_nla_action_pushdown(adt);
-
- /* get range of motion to bake, and the channels involved... */
-
- /* temporarily mute the action, and start keying to it */
-
- /* start keying... */
-
- /* unmute the action */
-}
-
-/* *************************************************** */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index b3f210dfba5..869e2849be5 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -75,6 +75,8 @@
#include "NOD_shader.h"
#include "NOD_texture.h"
+#include "DEG_depsgraph.h"
+
#define NODE_DEFAULT_MAX_WIDTH 700
/* Fallback types for undefined tree, nodes, sockets */
@@ -1211,6 +1213,56 @@ void nodeDetachNode(struct bNode *node)
}
}
+void nodePositionRelative(bNode *from_node, bNode *to_node, bNodeSocket *from_sock, bNodeSocket *to_sock)
+{
+ float offset_x;
+ int tot_sock_idx;
+
+ /* Socket to plug into. */
+ if (SOCK_IN == to_sock->in_out) {
+ offset_x = - (from_node->typeinfo->width + 50);
+ tot_sock_idx = BLI_listbase_count(&to_node->outputs);
+ tot_sock_idx += BLI_findindex(&to_node->inputs, to_sock);
+ }
+ else {
+ offset_x = to_node->typeinfo->width + 50;
+ tot_sock_idx = BLI_findindex(&to_node->outputs, to_sock);
+ }
+
+ BLI_assert(tot_sock_idx != -1);
+
+ float offset_y = U.widget_unit * tot_sock_idx;
+
+ /* Output socket. */
+ if (from_sock) {
+ if (SOCK_IN == from_sock->in_out) {
+ tot_sock_idx = BLI_listbase_count(&from_node->outputs);
+ tot_sock_idx += BLI_findindex(&from_node->inputs, from_sock);
+ }
+ else {
+ tot_sock_idx = BLI_findindex(&from_node->outputs, from_sock);
+ }
+ }
+
+ BLI_assert(tot_sock_idx != -1);
+
+ offset_y -= U.widget_unit * tot_sock_idx;
+
+ from_node->locx = to_node->locx + offset_x;
+ from_node->locy = to_node->locy - offset_y;
+}
+
+void nodePositionPropagate(bNode *node)
+{
+ for (bNodeSocket *nsock = node->inputs.first; nsock; nsock = nsock->next) {
+ if (nsock->link != NULL) {
+ bNodeLink *link = nsock->link;
+ nodePositionRelative(link->fromnode, link->tonode, link->fromsock, link->tosock);
+ nodePositionPropagate(link->fromnode);
+ }
+ }
+}
+
void ntreeInitDefault(bNodeTree *ntree)
{
ntree_set_typeinfo(ntree, NULL);
@@ -1592,54 +1644,6 @@ void BKE_node_preview_set_pixel(bNodePreview *preview, const float col[4], int x
}
}
-#if 0
-static void nodeClearPreview(bNode *node)
-{
- if (node->preview && node->preview->rect)
- memset(node->preview->rect, 0, MEM_allocN_len(node->preview->rect));
-}
-
-/* use it to enforce clear */
-void ntreeClearPreview(bNodeTree *ntree)
-{
- bNode *node;
-
- if (ntree == NULL)
- return;
-
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->typeinfo->flag & NODE_PREVIEW)
- nodeClearPreview(node);
- if (node->type == NODE_GROUP)
- ntreeClearPreview((bNodeTree *)node->id);
- }
-}
-
-/* hack warning! this function is only used for shader previews, and
- * since it gets called multiple times per pixel for Ztransp we only
- * add the color once. Preview gets cleared before it starts render though */
-void nodeAddToPreview(bNode *node, const float col[4], int x, int y, int do_manage)
-{
- bNodePreview *preview = node->preview;
- if (preview) {
- if (x >= 0 && y >= 0) {
- if (x < preview->xsize && y < preview->ysize) {
- unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
-
- if (do_manage) {
- linearrgb_to_srgb_uchar4(tar, col);
- }
- else {
- rgba_float_to_uchar(tar, col);
- }
- }
- //else printf("prv out bound x y %d %d\n", x, y);
- }
- //else printf("prv out bound x y %d %d\n", x, y);
- }
-}
-#endif
-
/* ************** Free stuff ********** */
/* goes over entire tree */
@@ -1939,15 +1943,15 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
-bNodeTree *ntreeFromID(ID *id)
+bNodeTree *ntreeFromID(const ID *id)
{
switch (GS(id->name)) {
- case ID_MA: return ((Material *)id)->nodetree;
- case ID_LA: return ((Lamp *)id)->nodetree;
- case ID_WO: return ((World *)id)->nodetree;
- case ID_TE: return ((Tex *)id)->nodetree;
- case ID_SCE: return ((Scene *)id)->nodetree;
- case ID_LS: return ((FreestyleLineStyle *)id)->nodetree;
+ case ID_MA: return ((const Material *)id)->nodetree;
+ case ID_LA: return ((const Lamp *)id)->nodetree;
+ case ID_WO: return ((const World *)id)->nodetree;
+ case ID_TE: return ((const Tex *)id)->nodetree;
+ case ID_SCE: return ((const Scene *)id)->nodetree;
+ case ID_LS: return ((const FreestyleLineStyle *)id)->nodetree;
default: return NULL;
}
}
@@ -1995,9 +1999,6 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
if (ntree) {
bNodeTree *ltree;
bNode *node;
- AnimData *adt;
-
- bAction *action_backup = NULL, *tmpact_backup = NULL;
BLI_spin_lock(&spin);
if (!ntree->duplilock) {
@@ -2007,23 +2008,16 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
BLI_mutex_lock(ntree->duplilock);
- /* Workaround for copying an action on each render!
- * set action to NULL so animdata actions don't get copied */
- adt = BKE_animdata_from_id(&ntree->id);
-
- if (adt) {
- action_backup = adt->action;
- tmpact_backup = adt->tmpact;
-
- adt->action = NULL;
- adt->tmpact = NULL;
- }
-
/* Make full copy outside of Main database.
* Note: previews are not copied here.
*/
- BKE_id_copy_ex(NULL, (ID *)ntree, (ID **)&ltree,
- LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_COPY_NO_PREVIEW, false);
+ BKE_id_copy_ex(
+ NULL, &ntree->id, (ID **)&ltree,
+ (LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_COPY_NO_PREVIEW |
+ LIB_ID_COPY_NO_ANIMDATA),
+ false);
ltree->flag |= NTREE_IS_LOCALIZED;
for (node = ltree->nodes.first; node; node = node->next) {
@@ -2032,31 +2026,19 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
}
}
- if (adt) {
- AnimData *ladt = BKE_animdata_from_id(&ltree->id);
-
- adt->action = ladt->action = action_backup;
- adt->tmpact = ladt->tmpact = tmpact_backup;
-
- if (action_backup)
- id_us_plus(&action_backup->id);
- if (tmpact_backup)
- id_us_plus(&tmpact_backup->id);
-
- }
- /* end animdata uglyness */
-
/* ensures only a single output node is enabled */
ntreeSetOutput(ntree);
for (node = ntree->nodes.first; node; node = node->next) {
/* store new_node pointer to original */
- node->new_node->new_node = node;
+ node->new_node->original = node;
}
if (ntree->typeinfo->localize)
ntree->typeinfo->localize(ltree, ntree);
+ ltree->id.tag |= LIB_TAG_LOCALIZED;
+
BLI_mutex_unlock(ntree->duplilock);
return ltree;
@@ -3127,77 +3109,6 @@ void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
}
-/* nodes that use ID data get synced with local data */
-void nodeSynchronizeID(bNode *node, bool copy_to_id)
-{
- if (node->id == NULL) return;
-
- if (ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) {
- bNodeSocket *sock;
- Material *ma = (Material *)node->id;
- int a;
- short check_flags = SOCK_UNAVAIL;
-
- if (!copy_to_id)
- check_flags |= SOCK_HIDDEN;
-
- /* hrmf, case in loop isn't super fast, but we don't edit 100s of material at same time either! */
- for (a = 0, sock = node->inputs.first; sock; sock = sock->next, a++) {
- if (!(sock->flag & check_flags)) {
- if (copy_to_id) {
- switch (a) {
- case MAT_IN_COLOR:
- copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
- case MAT_IN_SPEC:
- copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
- case MAT_IN_REFL:
- ma->ref = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_MIR:
- copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
- case MAT_IN_AMB:
- ma->amb = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_EMIT:
- ma->emit = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_SPECTRA:
- ma->spectra = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_RAY_MIRROR:
- ma->ray_mirror = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_ALPHA:
- ma->alpha = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- case MAT_IN_TRANSLUCENCY:
- ma->translucency = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
- }
- }
- else {
- switch (a) {
- case MAT_IN_COLOR:
- copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->r); break;
- case MAT_IN_SPEC:
- copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->specr); break;
- case MAT_IN_REFL:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ref; break;
- case MAT_IN_MIR:
- copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->mirr); break;
- case MAT_IN_AMB:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->amb; break;
- case MAT_IN_EMIT:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->emit; break;
- case MAT_IN_SPECTRA:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->spectra; break;
- case MAT_IN_RAY_MIRROR:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->ray_mirror; break;
- case MAT_IN_ALPHA:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->alpha; break;
- case MAT_IN_TRANSLUCENCY:
- ((bNodeSocketValueFloat *)sock->default_value)->value = ma->translucency; break;
- }
- }
- }
- }
- }
-}
-
-
/* ************* node type access ********** */
void nodeLabel(bNodeTree *ntree, bNode *node, char *label, int maxlen)
@@ -3424,11 +3335,6 @@ void node_type_internal_links(bNodeType *ntype, void (*update_internal_links)(bN
ntype->update_internal_links = update_internal_links;
}
-void node_type_compatibility(struct bNodeType *ntype, short compatibility)
-{
- ntype->compatibility = compatibility;
-}
-
/* callbacks for undefined types */
static bool node_undefined_poll(bNodeType *UNUSED(ntype), bNodeTree *UNUSED(nodetree))
@@ -3563,10 +3469,7 @@ static void registerShaderNodes(void)
{
register_node_type_sh_group();
- register_node_type_sh_output();
- register_node_type_sh_material();
register_node_type_sh_camera();
- register_node_type_sh_lamp();
register_node_type_sh_gamma();
register_node_type_sh_brightcontrast();
register_node_type_sh_value();
@@ -3577,9 +3480,8 @@ static void registerShaderNodes(void)
register_node_type_sh_mix_rgb();
register_node_type_sh_valtorgb();
register_node_type_sh_rgbtobw();
- register_node_type_sh_texture();
+ register_node_type_sh_shadertorgb();
register_node_type_sh_normal();
- register_node_type_sh_geom();
register_node_type_sh_mapping();
register_node_type_sh_curve_vec();
register_node_type_sh_curve_rgb();
@@ -3587,7 +3489,6 @@ static void registerShaderNodes(void)
register_node_type_sh_vect_math();
register_node_type_sh_vect_transform();
register_node_type_sh_squeeze();
- register_node_type_sh_material_ext();
register_node_type_sh_invert();
register_node_type_sh_seprgb();
register_node_type_sh_combrgb();
@@ -3633,6 +3534,7 @@ static void registerShaderNodes(void)
register_node_type_sh_add_shader();
register_node_type_sh_uvmap();
register_node_type_sh_uvalongstroke();
+ register_node_type_sh_eevee_specular();
register_node_type_sh_output_lamp();
register_node_type_sh_output_material();
@@ -3826,3 +3728,28 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter,
return true;
}
+
+/* -------------------------------------------------------------------- */
+/* NodeTree kernel functions */
+
+void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index)
+{
+ BLI_assert(layer_index != -1);
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
+ if (node->custom1 == layer_index) {
+ node->custom1 = 0;
+ }
+ else if (node->custom1 > layer_index) {
+ node->custom1--;
+ }
+ }
+ }
+}
+
+void BKE_nodetree_shading_params_eval(struct Depsgraph *depsgraph,
+ bNodeTree *ntree_dst,
+ const bNodeTree *ntree_src)
+{
+ DEG_debug_print_eval(depsgraph, __func__, ntree_src->id.name, ntree_dst);
+}
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index add7c1fd992..bd14de144da 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -39,9 +39,10 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
-#include "DNA_group_types.h"
+#include "DNA_gpencil_modifier_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
@@ -53,12 +54,13 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_shader_fx_types.h"
#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
#include "DNA_object_types.h"
-#include "DNA_property_types.h"
+#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "BLI_blenlib.h"
@@ -76,21 +78,21 @@
#include "BKE_idprop.h"
#include "BKE_armature.h"
#include "BKE_action.h"
-#include "BKE_bullet.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_animsys.h"
#include "BKE_anim.h"
+#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
-#include "BKE_group.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_icons.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
+#include "BKE_layer.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -103,20 +105,28 @@
#include "BKE_multires.h"
#include "BKE_node.h"
#include "BKE_object.h"
+#include "BKE_object_facemap.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "BKE_property.h"
+#include "BKE_lightprobe.h"
#include "BKE_rigidbody.h"
-#include "BKE_sca.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
+#include "BKE_shader_fx.h"
#include "BKE_speaker.h"
#include "BKE_softbody.h"
#include "BKE_subsurf.h"
+#include "BKE_subdiv_ccg.h"
#include "BKE_material.h"
#include "BKE_camera.h"
#include "BKE_image.h"
+#include "BKE_gpencil.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DRW_engine.h"
#ifdef WITH_MOD_FLUID
#include "LBM_fluidsim.h"
@@ -129,8 +139,6 @@
#include "CCGSubSurf.h"
#include "atomic_ops.h"
-#include "GPU_material.h"
-
/* Vertex parent modifies original BMesh which is not safe for threading.
* Ideally such a modification should be handled as a separate DAG update
* callback for mesh datablock, but for until it is actually supported use
@@ -152,16 +160,6 @@ void BKE_object_workob_clear(Object *workob)
workob->rotmode = ROT_MODE_EUL;
}
-void BKE_object_update_base_layer(struct Scene *scene, Object *ob)
-{
- Base *base = scene->base.first;
-
- while (base) {
- if (base->object == ob) base->lay = ob->lay;
- base = base->next;
- }
-}
-
void BKE_object_free_particlesystems(Object *ob)
{
ParticleSystem *psys;
@@ -173,42 +171,35 @@ void BKE_object_free_particlesystems(Object *ob)
void BKE_object_free_softbody(Object *ob)
{
- if (ob->soft) {
- sbFree(ob->soft);
- ob->soft = NULL;
- }
-}
-
-void BKE_object_free_bulletsoftbody(Object *ob)
-{
- if (ob->bsoft) {
- bsbFree(ob->bsoft);
- ob->bsoft = NULL;
- }
+ sbFree(ob);
}
void BKE_object_free_curve_cache(Object *ob)
{
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
- if (ob->curve_cache->path) {
- free_path(ob->curve_cache->path);
+ if (ob->runtime.curve_cache) {
+ BKE_displist_free(&ob->runtime.curve_cache->disp);
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ if (ob->runtime.curve_cache->path) {
+ free_path(ob->runtime.curve_cache->path);
}
- BKE_nurbList_free(&ob->curve_cache->deformed_nurbs);
- MEM_freeN(ob->curve_cache);
- ob->curve_cache = NULL;
+ BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs);
+ MEM_freeN(ob->runtime.curve_cache);
+ ob->runtime.curve_cache = NULL;
}
}
void BKE_object_free_modifiers(Object *ob, const int flag)
{
ModifierData *md;
+ GpencilModifierData *gp_md;
while ((md = BLI_pophead(&ob->modifiers))) {
modifier_free_ex(md, flag);
}
+ while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
+ BKE_gpencil_modifier_free_ex(gp_md, flag);
+ }
/* particle modifiers were freed, so free the particlesystems as well */
BKE_object_free_particlesystems(ob);
@@ -219,6 +210,15 @@ void BKE_object_free_modifiers(Object *ob, const int flag)
BKE_object_free_derived_caches(ob);
}
+void BKE_object_free_shaderfx(Object *ob, const int flag)
+{
+ ShaderFxData *fx;
+
+ while ((fx = BLI_pophead(&ob->shader_fx))) {
+ BKE_shaderfx_free_ex(fx, flag);
+ }
+}
+
void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
{
/* reset functionality */
@@ -241,6 +241,29 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
}
}
+void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData *hmd)
+{
+ if (hmd->object == NULL) {
+ return;
+ }
+ /* reset functionality */
+ bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
+
+ if (hmd->subtarget[0] && pchan) {
+ float imat[4][4], mat[4][4];
+
+ /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
+ mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
+
+ invert_m4_m4(imat, mat);
+ mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
+ }
+ else {
+ invert_m4_m4(hmd->object->imat, hmd->object->obmat);
+ mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
+ }
+}
+
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
const ModifierTypeInfo *mti;
@@ -265,7 +288,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
return true;
}
-void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
+void BKE_object_link_modifiers(Scene *scene, struct Object *ob_dst, const struct Object *ob_src)
{
ModifierData *md;
BKE_object_free_modifiers(ob_dst, 0);
@@ -291,7 +314,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
switch (md->type) {
case eModifierType_Softbody:
- BKE_object_copy_softbody(ob_dst, ob_src);
+ BKE_object_copy_softbody(ob_dst, ob_src, 0);
break;
case eModifierType_Skin:
/* ensure skin-node customdata exists */
@@ -304,7 +327,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
if (md->type == eModifierType_Multires) {
/* Has to be done after mod creation, but *before* we actually copy its settings! */
- multiresModifier_sync_levels_ex(ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
+ multiresModifier_sync_levels_ex(scene, ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
}
modifier_copyData(md, nmd);
@@ -317,6 +340,93 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
/* TODO: smoke?, cloth? */
}
+/* Copy CCG related data. Used to sync copy of mesh with reshaped original
+ * mesh.
+ */
+static void copy_ccg_data(Mesh *mesh_destination,
+ Mesh *mesh_source,
+ int layer_type)
+{
+ BLI_assert(mesh_destination->totloop == mesh_source->totloop);
+ CustomData *data_destination = &mesh_destination->ldata;
+ CustomData *data_source = &mesh_source->ldata;
+ const int num_elements = mesh_source->totloop;
+ if (!CustomData_has_layer(data_source, layer_type)) {
+ return;
+ }
+ const int layer_index = CustomData_get_layer_index(
+ data_destination, layer_type);
+ CustomData_free_layer(
+ data_destination, layer_type, num_elements, layer_index);
+ BLI_assert(!CustomData_has_layer(data_destination, layer_type));
+ CustomData_add_layer(
+ data_destination, layer_type, CD_CALLOC, NULL, num_elements);
+ BLI_assert(CustomData_has_layer(data_destination, layer_type));
+ CustomData_copy_layer_type_data(data_source, data_destination,
+ layer_type, 0, 0, num_elements);
+}
+
+static void object_update_from_subsurf_ccg(Object *object)
+{
+ /* Currently CCG is only created for Mesh objects. */
+ if (object->type != OB_MESH) {
+ return;
+ }
+ /* Object was never evaluated, so can not have CCG subdivision surface. */
+ Mesh *mesh_eval = object->runtime.mesh_eval;
+ if (mesh_eval == NULL) {
+ return;
+ }
+ SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg;
+ if (subdiv_ccg == NULL) {
+ return;
+ }
+ /* Check whether there is anything to be reshaped. */
+ if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) {
+ return;
+ }
+ const int tot_level = mesh_eval->runtime.subdiv_ccg_tot_level;
+ Object *object_orig = DEG_get_original_object(object);
+ Mesh *mesh_orig = (Mesh *)object_orig->data;
+ multiresModifier_reshapeFromCCG(tot_level, mesh_orig, subdiv_ccg);
+ /* NOTE: we need to reshape into an original mesh from main database,
+ * allowing:
+ *
+ * - Update copies of that mesh at any moment.
+ * - Save the file without doing extra reshape.
+ * - All the users of the mesh have updated displacement.
+ *
+ * However, the tricky part here is that we only know about sculpted
+ * state of a mesh on an object level, and object is being updated after
+ * mesh datablock is updated. This forces us to:
+ *
+ * - Update mesh datablock from object evaluation, which is technically
+ * forbidden, but there is no other place for this yet.
+ * - Reshape to the original mesh from main database, and then copy updated
+ * layer to copy of that mesh (since copy of the mesh has decoupled
+ * custom data layers).
+ *
+ * All this is defeating all the designs we need to follow to allow safe
+ * threaded evaluation, but this is as good as we can make it within the
+ * current sculpt//evaluated mesh design. This is also how we've survived
+ * with old DerivedMesh based solutions. So, while this is all wrong and
+ * needs reconsideration, doesn't seem to be a big stopper for real
+ * production artists.
+ */
+ /* TODO(sergey): Solve this somehow, to be fully stable for threaded
+ * evaluation environment.
+ */
+ /* NOTE: runtime.mesh_orig is what was before assigning mesh_eval,
+ * it is orig as in what was in object_eval->data before evaluating
+ * modifier stack.
+ *
+ * mesh_cow is a copy-on-written version od object_orig->data.
+ */
+ Mesh *mesh_cow = object->runtime.mesh_orig;
+ copy_ccg_data(mesh_cow, mesh_orig, CD_MDISPS);
+ copy_ccg_data(mesh_cow, mesh_orig, CD_GRID_PAINT_MASK);
+}
+
/* free data derived from mesh, called when mesh changes or is freed */
void BKE_object_free_derived_caches(Object *ob)
{
@@ -346,6 +456,38 @@ void BKE_object_free_derived_caches(Object *ob)
ob->bb = NULL;
}
+ object_update_from_subsurf_ccg(ob);
+ BKE_object_free_derived_mesh_caches(ob);
+
+ if (ob->runtime.mesh_eval != NULL) {
+ Mesh *mesh_eval = ob->runtime.mesh_eval;
+ /* Restore initial pointer. */
+ if (ob->data == mesh_eval) {
+ ob->data = ob->runtime.mesh_orig;
+ }
+ /* Evaluated mesh points to edit mesh, but does not own it. */
+ mesh_eval->edit_btmesh = NULL;
+ BKE_mesh_free(mesh_eval);
+ BKE_libblock_free_data(&mesh_eval->id, false);
+ MEM_freeN(mesh_eval);
+ ob->runtime.mesh_eval = NULL;
+ }
+ if (ob->runtime.mesh_deform_eval != NULL) {
+ Mesh *mesh_deform_eval = ob->runtime.mesh_deform_eval;
+ BKE_mesh_free(mesh_deform_eval);
+ BKE_libblock_free_data(&mesh_deform_eval->id, false);
+ MEM_freeN(mesh_deform_eval);
+ ob->runtime.mesh_deform_eval = NULL;
+ }
+
+ BKE_object_free_curve_cache(ob);
+
+ /* clear grease pencil data */
+ DRW_gpencil_freecache(ob);
+}
+
+void BKE_object_free_derived_mesh_caches(struct Object *ob)
+{
if (ob->derivedFinal) {
ob->derivedFinal->needsFree = 1;
ob->derivedFinal->release(ob->derivedFinal);
@@ -356,8 +498,6 @@ void BKE_object_free_derived_caches(Object *ob)
ob->derivedDeform->release(ob->derivedDeform);
ob->derivedDeform = NULL;
}
-
- BKE_object_free_curve_cache(ob);
}
void BKE_object_free_caches(Object *object)
@@ -381,14 +521,12 @@ void BKE_object_free_caches(Object *object)
for (md = object->modifiers.first; md != NULL; md = md->next) {
if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
- if (psmd->dm_final != NULL) {
- psmd->dm_final->needsFree = 1;
- psmd->dm_final->release(psmd->dm_final);
- psmd->dm_final = NULL;
- if (psmd->dm_deformed != NULL) {
- psmd->dm_deformed->needsFree = 1;
- psmd->dm_deformed->release(psmd->dm_deformed);
- psmd->dm_deformed = NULL;
+ if (psmd->mesh_final) {
+ BKE_id_free(NULL, psmd->mesh_final);
+ psmd->mesh_final = NULL;
+ if (psmd->mesh_original) {
+ BKE_id_free(NULL, psmd->mesh_original);
+ psmd->mesh_original = NULL;
}
psmd->flag |= eParticleSystemFlag_file_loaded;
update_flag |= OB_RECALC_DATA;
@@ -396,12 +534,21 @@ void BKE_object_free_caches(Object *object)
}
}
+ /* NOTE: If object is coming from a duplicator, it might be a temporary
+ * object created by dependency graph, which shares pointers with original
+ * object. In this case we can not free anything.
+ */
+ if ((object->base_flag & BASE_FROMDUPLI) == 0) {
+ BKE_object_free_derived_caches(object);
+ update_flag |= OB_RECALC_DATA;
+ }
+
/* Tag object for update, so once memory critical operation is over and
* scene update routines are back to it's business the object will be
* guaranteed to be in a known state.
*/
if (update_flag != 0) {
- DAG_id_tag_update(&object->id, update_flag);
+ DEG_id_tag_update(&object->id, update_flag);
}
}
@@ -410,8 +557,11 @@ void BKE_object_free(Object *ob)
{
BKE_animdata_free((ID *)ob, false);
+ DRW_drawdata_free((ID *)ob);
+
/* BKE_<id>_free shall never touch to ID->us. Never ever. */
BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
+ BKE_object_free_shaderfx(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
MEM_SAFE_FREE(ob->mat);
MEM_SAFE_FREE(ob->matbits);
@@ -419,6 +569,7 @@ void BKE_object_free(Object *ob)
MEM_SAFE_FREE(ob->bb);
BLI_freelistN(&ob->defbase);
+ BLI_freelistN(&ob->fmaps);
if (ob->pose) {
BKE_pose_free_ex(ob->pose, false);
ob->pose = NULL;
@@ -427,27 +578,14 @@ void BKE_object_free(Object *ob)
animviz_free_motionpath(ob->mpath);
ob->mpath = NULL;
}
- BKE_bproperty_free_list(&ob->prop);
-
- free_sensors(&ob->sensors);
- free_controllers(&ob->controllers);
- free_actuators(&ob->actuators);
BKE_constraints_free_ex(&ob->constraints, false);
free_partdeflect(ob->pd);
- BKE_rigidbody_free_object(ob);
+ BKE_rigidbody_free_object(ob, NULL);
BKE_rigidbody_free_constraint(ob);
- if (ob->soft) {
- sbFree(ob->soft);
- ob->soft = NULL;
- }
- if (ob->bsoft) {
- bsbFree(ob->bsoft);
- ob->bsoft = NULL;
- }
- GPU_lamp_free(ob);
+ sbFree(ob);
BKE_sculptsession_free(ob);
@@ -456,12 +594,12 @@ void BKE_object_free(Object *ob)
BLI_freelistN(&ob->lodlevels);
/* Free runtime curves data. */
- if (ob->curve_cache) {
- BKE_curve_bevelList_free(&ob->curve_cache->bev);
- if (ob->curve_cache->path)
- free_path(ob->curve_cache->path);
- MEM_freeN(ob->curve_cache);
- ob->curve_cache = NULL;
+ if (ob->runtime.curve_cache) {
+ BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev);
+ if (ob->runtime.curve_cache->path)
+ free_path(ob->runtime.curve_cache->path);
+ MEM_freeN(ob->runtime.curve_cache);
+ ob->runtime.curve_cache = NULL;
}
BKE_previewimg_free(&ob->preview);
@@ -470,63 +608,135 @@ void BKE_object_free(Object *ob)
/* actual check for internal data, not context or flags */
bool BKE_object_is_in_editmode(const Object *ob)
{
- if (ob->data == NULL)
+ if (ob->data == NULL) {
return false;
+ }
+ switch (ob->type) {
+ case OB_MESH:
+ return ((Mesh *)ob->data)->edit_btmesh != NULL;
+ case OB_ARMATURE:
+ return ((bArmature *)ob->data)->edbo != NULL;
+ case OB_FONT:
+ return ((Curve *)ob->data)->editfont != NULL;
+ case OB_MBALL:
+ return ((MetaBall *)ob->data)->editelems != NULL;
+ case OB_LATTICE:
+ return ((Lattice *)ob->data)->editlatt != NULL;
+ case OB_SURF:
+ case OB_CURVE:
+ return ((Curve *)ob->data)->editnurb != NULL;
+ default:
+ return false;
+ }
+}
+
+bool BKE_object_is_in_editmode_vgroup(const Object *ob)
+{
+ return (OB_TYPE_SUPPORT_VGROUP(ob->type) &&
+ BKE_object_is_in_editmode(ob));
+}
+
+bool BKE_object_data_is_in_editmode(const ID *id)
+{
+ const short type = GS(id->name);
+ BLI_assert(OB_DATA_SUPPORT_EDITMODE(type));
+ switch (type) {
+ case ID_ME:
+ return ((const Mesh *)id)->edit_btmesh != NULL;
+ case ID_CU:
+ return (
+ (((const Curve *)id)->editnurb != NULL) ||
+ (((const Curve *)id)->editfont != NULL)
+ );
+ case ID_MB:
+ return ((const MetaBall *)id)->editelems != NULL;
+ case ID_LT:
+ return ((const Lattice *)id)->editlatt != NULL;
+ case ID_AR:
+ return ((const bArmature *)id)->edbo != NULL;
+ default:
+ BLI_assert(0);
+ return false;
+ }
+}
+
+bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
+{
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- if (me->edit_btmesh)
- return true;
+ return ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
+ (me->edit_btmesh == NULL) &&
+ (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX));
}
- else if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
- if (arm->edbo)
+ return false;
+}
+
+bool BKE_object_has_mode_data(const struct Object *ob, eObjectMode object_mode)
+{
+ if (object_mode & OB_MODE_EDIT) {
+ if (BKE_object_is_in_editmode(ob)) {
return true;
+ }
}
- else if (ob->type == OB_FONT) {
- Curve *cu = ob->data;
-
- if (cu->editfont)
+ else if (object_mode & OB_MODE_VERTEX_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
return true;
+ }
}
- else if (ob->type == OB_MBALL) {
- MetaBall *mb = ob->data;
-
- if (mb->editelems)
+ else if (object_mode & OB_MODE_WEIGHT_PAINT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
return true;
+ }
}
- else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
-
- if (lt->editlatt)
+ else if (object_mode & OB_MODE_SCULPT) {
+ if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
return true;
+ }
}
- else if (ob->type == OB_SURF || ob->type == OB_CURVE) {
- Curve *cu = ob->data;
-
- if (cu->editnurb)
+ else if (object_mode & OB_MODE_POSE) {
+ if (ob->pose != NULL) {
return true;
+ }
}
return false;
}
-bool BKE_object_is_in_editmode_vgroup(const Object *ob)
+bool BKE_object_is_mode_compat(const struct Object *ob, eObjectMode object_mode)
{
- return (OB_TYPE_SUPPORT_VGROUP(ob->type) &&
- BKE_object_is_in_editmode(ob));
+ return ((ob->mode == object_mode) ||
+ (ob->mode & object_mode) != 0);
}
-bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
+/**
+ * Return if the object is visible, as evaluated by depsgraph
+ */
+bool BKE_object_is_visible(const Object *ob, const eObjectVisibilityCheck mode)
{
- if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
- return ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
- (me->edit_btmesh == NULL) &&
- (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX));
+ if ((ob->base_flag & BASE_VISIBLE) == 0) {
+ return false;
}
- return false;
+ if (mode == OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) {
+ return true;
+ }
+
+ if (((ob->transflag & OB_DUPLI) == 0) &&
+ (ob->particlesystem.first == NULL))
+ {
+ return true;
+ }
+
+ switch (mode) {
+ case OB_VISIBILITY_CHECK_FOR_VIEWPORT:
+ return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_VIEWPORT) != 0);
+ case OB_VISIBILITY_CHECK_FOR_RENDER:
+ return ((ob->duplicator_visibility_flag & OB_DUPLI_FLAG_RENDER) != 0);
+ default:
+ BLI_assert(!"Object visible test mode not supported.");
+ return false;
+ }
}
bool BKE_object_exists_check(Main *bmain, const Object *obtest)
@@ -554,11 +764,12 @@ static const char *get_obdata_defname(int type)
case OB_FONT: return DATA_("Text");
case OB_MBALL: return DATA_("Mball");
case OB_CAMERA: return DATA_("Camera");
- case OB_LAMP: return DATA_("Lamp");
+ case OB_LAMP: return DATA_("Light");
case OB_LATTICE: return DATA_("Lattice");
case OB_ARMATURE: return DATA_("Armature");
case OB_SPEAKER: return DATA_("Speaker");
case OB_EMPTY: return DATA_("Empty");
+ case OB_GPENCIL: return DATA_("GPencil");
default:
printf("get_obdata_defname: Internal error, bad type: %d\n", type);
return DATA_("Empty");
@@ -582,6 +793,8 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
case OB_LATTICE: return BKE_lattice_add(bmain, name);
case OB_ARMATURE: return BKE_armature_add(bmain, name);
case OB_SPEAKER: return BKE_speaker_add(bmain, name);
+ case OB_LIGHTPROBE:return BKE_lightprobe_add(bmain, name);
+ case OB_GPENCIL: return BKE_gpencil_data_addnew(bmain, name);
case OB_EMPTY: return NULL;
default:
printf("%s: Internal error, bad type: %d\n", __func__, type);
@@ -619,6 +832,10 @@ void BKE_object_init(Object *ob)
ob->dt = OB_TEXTURE;
ob->empty_drawtype = OB_PLAINAXES;
ob->empty_drawsize = 1.0;
+ ob->empty_image_depth = OB_EMPTY_IMAGE_DEPTH_DEFAULT;
+ ob->empty_image_visibility_flag = (
+ OB_EMPTY_IMAGE_VISIBLE_PERSPECTIVE |
+ OB_EMPTY_IMAGE_VISIBLE_ORTHOGRAPHIC);
if (ob->type == OB_EMPTY) {
copy_v2_fl(ob->ima_ofs, -0.5f);
}
@@ -636,26 +853,10 @@ void BKE_object_init(Object *ob)
ob->dupsta = 1; ob->dupend = 100;
ob->dupfacesca = 1.0;
- /* Game engine defaults*/
- ob->mass = ob->inertia = 1.0f;
- ob->formfactor = 0.4f;
- ob->damping = 0.04f;
- ob->rdamping = 0.1f;
- ob->anisotropicFriction[0] = 1.0f;
- ob->anisotropicFriction[1] = 1.0f;
- ob->anisotropicFriction[2] = 1.0f;
- ob->gameflag = OB_PROP | OB_COLLISION;
- ob->margin = 0.04f;
- ob->init_state = 1;
- ob->state = 1;
- ob->obstacleRad = 1.0f;
- ob->step_height = 0.15f;
- ob->jump_speed = 10.0f;
- ob->fall_speed = 55.0f;
- ob->max_jumps = 1;
ob->col_group = 0x01;
ob->col_mask = 0xffff;
ob->preview = NULL;
+ ob->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER;
/* NT fluid sim defaults */
ob->fluidsimSettings = NULL;
@@ -664,6 +865,8 @@ void BKE_object_init(Object *ob)
/* Animation Visualization defaults */
animviz_settings_init(&ob->avs);
+
+ ob->display.flag = OB_SHOW_SHADOW;
}
/* more general add: creates minimum required data, but without vertices etc. */
@@ -676,6 +879,9 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
ob = BKE_libblock_alloc(bmain, ID_OB, name, 0);
+ /* We increase object user count when linking to Collections. */
+ id_us_min(&ob->id);
+
/* default object vars */
ob->type = type;
@@ -684,168 +890,112 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
return ob;
}
-/* general add: to scene, with layer from area and default name */
-/* creates minimum required data, but without vertices etc. */
-Object *BKE_object_add(
- Main *bmain, Scene *scene,
- int type, const char *name)
+
+static Object *object_add_common(Main *bmain, ViewLayer *view_layer, int type, const char *name)
{
Object *ob;
- Base *base;
ob = BKE_object_add_only_object(bmain, type, name);
-
ob->data = BKE_object_obdata_add_from_type(bmain, type, name);
+ BKE_view_layer_base_deselect_all(view_layer);
- ob->lay = scene->lay;
-
- base = BKE_scene_base_add(scene, ob);
- BKE_scene_base_deselect_all(scene);
- BKE_scene_base_select(scene, base);
- DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
+ DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
return ob;
}
-
-#ifdef WITH_GAMEENGINE
-
-void BKE_object_lod_add(Object *ob)
-{
- LodLevel *lod = MEM_callocN(sizeof(LodLevel), "LoD Level");
- LodLevel *last = ob->lodlevels.last;
-
- /* If the lod list is empty, initialize it with the base lod level */
- if (!last) {
- LodLevel *base = MEM_callocN(sizeof(LodLevel), "Base LoD Level");
- BLI_addtail(&ob->lodlevels, base);
- base->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
- base->source = ob;
- base->obhysteresis = 10;
- last = ob->currentlod = base;
- }
-
- lod->distance = last->distance + 25.0f;
- lod->obhysteresis = 10;
- lod->flags = OB_LOD_USE_MESH | OB_LOD_USE_MAT;
-
- BLI_addtail(&ob->lodlevels, lod);
-}
-
-static int lod_cmp(const void *a, const void *b)
-{
- const LodLevel *loda = a;
- const LodLevel *lodb = b;
-
- if (loda->distance < lodb->distance) return -1;
- return loda->distance > lodb->distance;
-}
-
-void BKE_object_lod_sort(Object *ob)
-{
- BLI_listbase_sort(&ob->lodlevels, lod_cmp);
-}
-
-bool BKE_object_lod_remove(Object *ob, int level)
+/**
+ * General add: to scene, with layer from area and default name
+ *
+ * Object is added to the active Collection.
+ * If there is no linked collection to the active ViewLayer we create a new one.
+ */
+/* creates minimum required data, but without vertices etc. */
+Object *BKE_object_add(
+ Main *bmain, Scene *UNUSED(scene), ViewLayer *view_layer,
+ int type, const char *name)
{
- LodLevel *rem;
-
- if (level < 1 || level > BLI_listbase_count(&ob->lodlevels) - 1)
- return false;
-
- rem = BLI_findlink(&ob->lodlevels, level);
+ Object *ob;
+ Base *base;
+ LayerCollection *layer_collection;
- if (rem == ob->currentlod) {
- ob->currentlod = rem->prev;
- }
+ ob = object_add_common(bmain, view_layer, type, name);
- BLI_remlink(&ob->lodlevels, rem);
- MEM_freeN(rem);
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
- /* If there are no user defined lods, remove the base lod as well */
- if (BLI_listbase_is_single(&ob->lodlevels)) {
- LodLevel *base = ob->lodlevels.first;
- BLI_remlink(&ob->lodlevels, base);
- MEM_freeN(base);
- ob->currentlod = NULL;
- }
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
- return true;
+ return ob;
}
-static LodLevel *lod_level_select(Object *ob, const float camera_position[3])
+/**
+ * Add a new object, using another one as a reference
+ *
+ * \param ob_src object to use to determine the collections of the new object.
+ */
+Object *BKE_object_add_from(
+ Main *bmain, Scene *scene, ViewLayer *view_layer,
+ int type, const char *name, Object *ob_src)
{
- LodLevel *current = ob->currentlod;
- float dist_sq;
-
- if (!current) return NULL;
-
- dist_sq = len_squared_v3v3(ob->obmat[3], camera_position);
+ Object *ob;
+ Base *base;
- if (dist_sq < SQUARE(current->distance)) {
- /* check for higher LoD */
- while (current->prev && dist_sq < SQUARE(current->distance)) {
- current = current->prev;
- }
- }
- else {
- /* check for lower LoD */
- while (current->next && dist_sq > SQUARE(current->next->distance)) {
- current = current->next;
- }
- }
+ ob = object_add_common(bmain, view_layer, type, name);
+ BKE_collection_object_add_from(bmain, scene, ob_src, ob);
- return current;
-}
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
-bool BKE_object_lod_is_usable(Object *ob, Scene *scene)
-{
- bool active = (scene) ? ob == OBACT : false;
- return (ob->mode == OB_MODE_OBJECT || !active);
+ return ob;
}
-void BKE_object_lod_update(Object *ob, const float camera_position[3])
+/**
+ * Add a new object, but assign the given datablock as the ob->data
+ * for the newly created object.
+ *
+ * \param data The datablock to assign as ob->data for the new object.
+ * This is assumed to be of the correct type.
+ * \param do_id_user If true, id_us_plus() will be called on data when
+ * assigning it to the object.
+ */
+Object *BKE_object_add_for_data(
+ Main *bmain, ViewLayer *view_layer,
+ int type, const char *name, ID *data, bool do_id_user)
{
- LodLevel *cur_level = ob->currentlod;
- LodLevel *new_level = lod_level_select(ob, camera_position);
-
- if (new_level != cur_level) {
- ob->currentlod = new_level;
- }
-}
+ Object *ob;
+ Base *base;
+ LayerCollection *layer_collection;
-static Object *lod_ob_get(Object *ob, Scene *scene, int flag)
-{
- LodLevel *current = ob->currentlod;
+ /* same as object_add_common, except we don't create new ob->data */
+ ob = BKE_object_add_only_object(bmain, type, name);
+ ob->data = data;
+ if (do_id_user) id_us_plus(data);
- if (!current || !BKE_object_lod_is_usable(ob, scene))
- return ob;
+ BKE_view_layer_base_deselect_all(view_layer);
+ DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- while (current->prev && (!(current->flags & flag) || !current->source || current->source->type != OB_MESH)) {
- current = current->prev;
- }
+ layer_collection = BKE_layer_collection_get_active(view_layer);
+ BKE_collection_object_add(bmain, layer_collection->collection, ob);
- return current->source;
-}
+ base = BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
-struct Object *BKE_object_lod_meshob_get(Object *ob, Scene *scene)
-{
- return lod_ob_get(ob, scene, OB_LOD_USE_MESH);
-}
-
-struct Object *BKE_object_lod_matob_get(Object *ob, Scene *scene)
-{
- return lod_ob_get(ob, scene, OB_LOD_USE_MAT);
+ return ob;
}
-#endif /* WITH_GAMEENGINE */
-
-SoftBody *copy_softbody(const SoftBody *sb, const int flag)
+void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag)
{
+ SoftBody *sb = ob_src->soft;
SoftBody *sbn;
+ bool tagged_no_main = ob_dst->id.tag & LIB_TAG_NO_MAIN;
- if (sb == NULL) return(NULL);
+ ob_dst->softflag = ob_src->softflag;
+ if (sb == NULL) {
+ ob_dst->soft = NULL;
+ return;
+ }
sbn = MEM_dupallocN(sb);
@@ -878,64 +1028,27 @@ SoftBody *copy_softbody(const SoftBody *sb, const int flag)
sbn->scratch = NULL;
- sbn->pointcache = BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches, flag);
+ if (tagged_no_main == 0) {
+ sbn->shared = MEM_dupallocN(sb->shared);
+ sbn->shared->pointcache = BKE_ptcache_copy_list(&sbn->shared->ptcaches, &sb->shared->ptcaches, flag);
+ }
if (sb->effector_weights)
sbn->effector_weights = MEM_dupallocN(sb->effector_weights);
- return sbn;
-}
-
-BulletSoftBody *copy_bulletsoftbody(const BulletSoftBody *bsb, const int UNUSED(flag))
-{
- BulletSoftBody *bsbn;
-
- if (bsb == NULL)
- return NULL;
- bsbn = MEM_dupallocN(bsb);
- /* no pointer in this structure yet */
- return bsbn;
+ ob_dst->soft = sbn;
}
ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int flag)
{
- ParticleSystem *psysn;
- ParticleData *pa;
- int p;
-
- psysn = MEM_dupallocN(psys);
- psysn->particles = MEM_dupallocN(psys->particles);
- psysn->child = MEM_dupallocN(psys->child);
-
- if (psys->part->type == PART_HAIR) {
- for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++)
- pa->hair = MEM_dupallocN(pa->hair);
- }
-
- if (psysn->particles && (psysn->particles->keys || psysn->particles->boid)) {
- ParticleKey *key = psysn->particles->keys;
- BoidParticle *boid = psysn->particles->boid;
-
- if (key)
- key = MEM_dupallocN(key);
-
- if (boid)
- boid = MEM_dupallocN(boid);
+ ParticleSystem *psysn = MEM_dupallocN(psys);
- for (p = 0, pa = psysn->particles; p < psysn->totpart; p++, pa++) {
- if (boid)
- pa->boid = boid++;
- if (key) {
- pa->keys = key;
- key += pa->totkey;
- }
- }
- }
+ psys_copy_particles(psysn, psys);
if (psys->clmd) {
psysn->clmd = (ClothModifierData *)modifier_new(eModifierType_Cloth);
modifier_copyData_ex((ModifierData *)psys->clmd, (ModifierData *)psysn->clmd, flag);
- psys->hair_in_dm = psys->hair_out_dm = NULL;
+ psys->hair_in_mesh = psys->hair_out_mesh = NULL;
}
BLI_duplicatelist(&psysn->targets, &psys->targets);
@@ -947,13 +1060,12 @@ ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys, const int f
psysn->effectors = NULL;
psysn->tree = NULL;
psysn->bvhtree = NULL;
+ psysn->batch_cache = NULL;
BLI_listbase_clear(&psysn->pathcachebufs);
BLI_listbase_clear(&psysn->childcachebufs);
- psysn->renderdata = NULL;
- /* XXX Never copy caches here? */
- psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag & ~LIB_ID_COPY_CACHES);
+ psysn->pointcache = BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches, flag);
/* XXX - from reading existing code this seems correct but intended usage of
* pointcache should /w cloth should be added in 'ParticleSystem' - campbell */
@@ -1013,14 +1125,6 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const
}
}
-void BKE_object_copy_softbody(Object *ob_dst, const Object *ob_src)
-{
- if (ob_src->soft) {
- ob_dst->softflag = ob_src->softflag;
- ob_dst->soft = copy_softbody(ob_src->soft, 0);
- }
-}
-
static void copy_object_pose(Object *obn, const Object *ob, const int flag)
{
bPoseChannel *chan;
@@ -1087,12 +1191,103 @@ Object *BKE_object_pose_armature_get(Object *ob)
ob = modifiers_isDeformedByArmature(ob);
+ /* Only use selected check when non-active. */
if (BKE_object_pose_context_check(ob))
return ob;
return NULL;
}
+Object *BKE_object_pose_armature_get_visible(Object *ob, ViewLayer *view_layer)
+{
+ Object *ob_armature = BKE_object_pose_armature_get(ob);
+ if (ob_armature) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob_armature);
+ if (base) {
+ if (BASE_VISIBLE(base)) {
+ return ob_armature;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Access pose array with special check to get pose object when in weight paint mode.
+ */
+Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer, uint *r_objects_len, bool unique)
+{
+ Object *ob_active = OBACT(view_layer);
+ Object *ob_pose = BKE_object_pose_armature_get(ob_active);
+ Object **objects = NULL;
+ if (ob_pose == ob_active) {
+ objects = BKE_view_layer_array_from_objects_in_mode(
+ view_layer, r_objects_len, {
+ .object_mode = OB_MODE_POSE,
+ .no_dup_data = unique});
+ }
+ else if (ob_pose != NULL) {
+ *r_objects_len = 1;
+ objects = MEM_mallocN(sizeof(*objects), __func__);
+ objects[0] = ob_pose;
+ }
+ else {
+ *r_objects_len = 0;
+ objects = MEM_mallocN(0, __func__);
+ }
+ return objects;
+}
+Object **BKE_object_pose_array_get_unique(ViewLayer *view_layer, uint *r_objects_len)
+{
+ return BKE_object_pose_array_get_ex(view_layer, r_objects_len, true);
+}
+Object **BKE_object_pose_array_get(ViewLayer *view_layer, uint *r_objects_len)
+{
+ return BKE_object_pose_array_get_ex(view_layer, r_objects_len, false);
+}
+
+Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer, uint *r_bases_len, bool unique)
+{
+ Base *base_active = BASACT(view_layer);
+ Object *ob_pose = base_active ? BKE_object_pose_armature_get(base_active->object) : NULL;
+ Base *base_pose = NULL;
+ Base **bases = NULL;
+
+ if (base_active) {
+ if (ob_pose == base_active->object) {
+ base_pose = base_active;
+ }
+ else {
+ base_pose = BKE_view_layer_base_find(view_layer, ob_pose);
+ }
+ }
+
+ if (base_active && (base_pose == base_active)) {
+ bases = BKE_view_layer_array_from_bases_in_mode(
+ view_layer, r_bases_len, {
+ .object_mode = OB_MODE_POSE,
+ .no_dup_data = unique});
+ }
+ else if (base_pose != NULL) {
+ *r_bases_len = 1;
+ bases = MEM_mallocN(sizeof(*bases), __func__);
+ bases[0] = base_pose;
+ }
+ else {
+ *r_bases_len = 0;
+ bases = MEM_mallocN(0, __func__);
+ }
+ return bases;
+}
+Base **BKE_object_pose_base_array_get_unique(ViewLayer *view_layer, uint *r_bases_len)
+{
+ return BKE_object_pose_base_array_get_ex(view_layer, r_bases_len, true);
+}
+Base **BKE_object_pose_base_array_get(ViewLayer *view_layer, uint *r_bases_len)
+{
+ return BKE_object_pose_base_array_get_ex(view_layer, r_bases_len, false);
+}
+
void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
{
copy_v3_v3(ob_tar->loc, ob_src->loc);
@@ -1112,9 +1307,14 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
*
* \param flag Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
-void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_src, const int flag)
+void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag)
{
ModifierData *md;
+ GpencilModifierData *gmd;
+ ShaderFxData *fx;
+
+ /* Do not copy runtime data. */
+ BKE_object_runtime_reset(ob_dst);
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
@@ -1134,7 +1334,6 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
if (ob_src->iuser) ob_dst->iuser = MEM_dupallocN(ob_src->iuser);
if (ob_src->bb) ob_dst->bb = MEM_dupallocN(ob_src->bb);
- ob_dst->flag &= ~OB_FROMGROUP;
BLI_listbase_clear(&ob_dst->modifiers);
@@ -1145,21 +1344,37 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
BLI_addtail(&ob_dst->modifiers, nmd);
}
- BLI_listbase_clear(&ob_dst->prop);
- BKE_bproperty_copy_list(&ob_dst->prop, &ob_src->prop);
+ BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
+
+ for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) {
+ GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
+ BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
+ BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata);
+ BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
+ }
+
+ BLI_listbase_clear(&ob_dst->shader_fx);
- BKE_sca_logic_copy(ob_dst, ob_src, flag_subdata);
+ for (fx = ob_src->shader_fx.first; fx; fx = fx->next) {
+ ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
+ BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
+ BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata);
+ BLI_addtail(&ob_dst->shader_fx, nfx);
+ }
if (ob_src->pose) {
copy_object_pose(ob_dst, ob_src, flag_subdata);
/* backwards compat... non-armatures can get poses in older files? */
- if (ob_src->type == OB_ARMATURE)
- BKE_pose_rebuild(ob_dst, ob_dst->data);
+ if (ob_src->type == OB_ARMATURE) {
+ const bool do_pose_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0;
+ BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user);
+ }
}
defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase);
+ BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps);
BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true);
- ob_dst->mode = OB_MODE_OBJECT;
+ ob_dst->mode = ob_dst->type != OB_GPENCIL ? OB_MODE_OBJECT : ob_dst->mode;
ob_dst->sculpt = NULL;
if (ob_src->pd) {
@@ -1168,8 +1383,7 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
ob_dst->pd->rng = MEM_dupallocN(ob_src->pd->rng);
}
}
- ob_dst->soft = copy_softbody(ob_src->soft, flag_subdata);
- ob_dst->bsoft = copy_bulletsoftbody(ob_src->bsoft, flag_subdata);
+ BKE_object_copy_softbody(ob_dst, ob_src, flag_subdata);
ob_dst->rigidbody_object = BKE_rigidbody_copy_object(ob_src, flag_subdata);
ob_dst->rigidbody_constraint = BKE_rigidbody_copy_constraint(ob_src, flag_subdata);
@@ -1178,16 +1392,14 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_
ob_dst->derivedDeform = NULL;
ob_dst->derivedFinal = NULL;
- BLI_listbase_clear(&ob_dst->gpulamp);
+ BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
- ob_dst->mpath = NULL;
+ ob_dst->avs = ob_src->avs;
+ ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);
copy_object_lod(ob_dst, ob_src, flag_subdata);
- /* Do not copy runtime curve data. */
- ob_dst->curve_cache = NULL;
-
/* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */
BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id);
@@ -1202,6 +1414,10 @@ Object *BKE_object_copy(Main *bmain, const Object *ob)
{
Object *ob_copy;
BKE_id_copy_ex(bmain, &ob->id, (ID **)&ob_copy, 0, false);
+
+ /* We increase object user count when linking to Collections. */
+ id_us_min(&ob_copy->id);
+
return ob_copy;
}
@@ -1325,9 +1541,9 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* proxy rule: lib_object->proxy_from == the one we borrow from, set temporally while object_update */
/* local_object->proxy == pointer to library object, saved in files and read */
-/* local_object->proxy_group == pointer to group dupli-object, saved in files and read */
+/* local_object->proxy_group == pointer to collection dupli-object, saved in files and read */
-void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
+void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob)
{
/* paranoia checks */
if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) {
@@ -1336,24 +1552,24 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
}
ob->proxy = target;
- ob->proxy_group = gob;
+ ob->proxy_group = cob;
id_lib_extern(&target->id);
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
- DAG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+ DEG_id_tag_update(&target->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
/* copy transform
- * - gob means this proxy comes from a group, just apply the matrix
+ * - cob means this proxy comes from a collection, just apply the matrix
* so the object wont move from its dupli-transform.
*
- * - no gob means this is being made from a linked object,
+ * - no cob means this is being made from a linked object,
* this is closer to making a copy of the object - in-place. */
- if (gob) {
+ if (cob) {
ob->rotmode = target->rotmode;
- mul_m4_m4m4(ob->obmat, gob->obmat, target->obmat);
- if (gob->dup_group) { /* should always be true */
+ mul_m4_m4m4(ob->obmat, cob->obmat, target->obmat);
+ if (cob->dup_group) { /* should always be true */
float tvec[3];
- mul_v3_mat3_m4v3(tvec, ob->obmat, gob->dup_group->dupli_ofs);
+ mul_v3_mat3_m4v3(tvec, ob->obmat, cob->dup_group->dupli_ofs);
sub_v3_v3(ob->obmat[3], tvec);
}
BKE_object_apply_mat4(ob, ob->obmat, false, true);
@@ -1402,7 +1618,7 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
if (target->type == OB_ARMATURE) {
copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */
BKE_pose_rest(ob->pose); /* clear all transforms in channels */
- BKE_pose_rebuild(ob, ob->data); /* set all internal links */
+ BKE_pose_rebuild(bmain, ob, ob->data, true); /* set all internal links */
armature_set_id_extern(ob);
}
@@ -1438,6 +1654,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
ob->empty_drawsize *= size;
break;
}
+ case OB_GPENCIL:
+ {
+ ob->empty_drawsize *= size;
+ break;
+ }
case OB_FONT:
{
Curve *cu = ob->data;
@@ -1662,7 +1883,7 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
if (ob->parent) {
float par_imat[4][4];
- BKE_object_get_parent_matrix(NULL, ob, ob->parent, par_imat);
+ BKE_object_get_parent_matrix(NULL, NULL, ob, ob->parent, par_imat);
invert_m4(par_imat);
mul_m4_m4m4(mat, par_imat, ob->obmat);
}
@@ -1675,23 +1896,31 @@ void BKE_object_matrix_local_get(struct Object *ob, float mat[4][4])
int enable_cu_speed = 1;
/**
- * \param scene: Used when curve cache needs to be calculated, or for dupli-frame time.
+ * \param depsgraph: Used for dupli-frame time.
* \return success if \a mat is set.
*/
-static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
+static bool ob_parcurve(Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob, Object *par, float mat[4][4])
{
Curve *cu = par->data;
float vec[4], dir[3], quat[4], radius, ctime;
+ /* TODO: Make sure this doesn't crash. */
+#if 0
/* only happens on reload file, but violates depsgraph still... fix! */
if (par->curve_cache == NULL) {
if (scene == NULL) {
return false;
}
- BKE_displist_make_curveTypes(scene, par, 0);
+ BKE_displist_make_curveTypes(depsgraph, scene, par, 0);
+ }
+#else
+ /* See: T56619 */
+ if (par->runtime.curve_cache == NULL) {
+ return false;
}
+#endif
- if (par->curve_cache->path == NULL) {
+ if (par->runtime.curve_cache->path == NULL) {
return false;
}
@@ -1714,11 +1943,11 @@ static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
}
else {
/* For dupli-frames only */
- if (scene == NULL) {
+ if (depsgraph == NULL) {
return false;
}
- ctime = BKE_scene_frame_get(scene);
+ ctime = DEG_get_ctime(depsgraph);
if (cu->pathlen) {
ctime /= cu->pathlen;
}
@@ -1732,21 +1961,7 @@ static bool ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
if (where_on_path(par, ctime, vec, dir, (cu->flag & CU_FOLLOW) ? quat : NULL, &radius, NULL)) {
if (cu->flag & CU_FOLLOW) {
-#if 0
- float si, q[4];
- vec_to_quat(quat, dir, ob->trackflag, ob->upflag);
-
- /* the tilt */
- normalize_v3(dir);
- q[0] = cosf(0.5 * vec[3]);
- si = sinf(0.5 * vec[3]);
- q[1] = -si * dir[0];
- q[2] = -si * dir[1];
- q[3] = -si * dir[2];
- mul_qt_qtqt(quat, q, quat);
-#else
quat_apply_track(quat, ob->trackflag, ob->upflag);
-#endif
normalize_qt(quat);
quat_to_mat4(mat, quat);
}
@@ -1806,18 +2021,23 @@ static void give_parvert(Object *par, int nr, float vec[3])
if (par->type == OB_MESH) {
Mesh *me = par->data;
BMEditMesh *em = me->edit_btmesh;
- DerivedMesh *dm;
+ DerivedMesh *dm = NULL;
+ Mesh *me_eval = (em) ? em->mesh_eval_final : par->runtime.mesh_eval;
- dm = (em) ? em->derivedFinal : par->derivedFinal;
+ /* Keep this until subsurf code ported away from derived mesh - campbell. */
+ dm = par->derivedFinal;
+ if (dm && dm->type != DM_TYPE_CCGDM) {
+ dm = NULL;
+ }
- if (dm) {
+ if (me_eval) {
int count = 0;
- int numVerts = dm->getNumVerts(dm);
+ const int numVerts = me_eval->totvert;
if (nr < numVerts) {
bool use_special_ss_case = false;
- if (dm->type == DM_TYPE_CCGDM) {
+ if (dm && dm->type == DM_TYPE_CCGDM) {
ModifierData *md;
VirtualModifierData virtualModifierData;
use_special_ss_case = true;
@@ -1836,7 +2056,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
if (!use_special_ss_case) {
/* avoid dm->getVertDataArray() since it allocates arrays in the dm (not thread safe) */
- if (em && dm->type == DM_TYPE_EDITBMESH) {
+ if (em && me_eval->runtime.is_original) {
if (em->bm->elem_table_dirty & BM_VERT) {
#ifdef VPARENT_THREADING_HACK
BLI_mutex_lock(&vparent_lock);
@@ -1863,27 +2083,21 @@ static void give_parvert(Object *par, int nr, float vec[3])
count++;
}
}
- else if (CustomData_has_layer(&dm->vertData, CD_ORIGINDEX) &&
- !(em && dm->type == DM_TYPE_EDITBMESH))
+ else if (CustomData_has_layer(&me_eval->vdata, CD_ORIGINDEX) &&
+ !(em && me_eval->runtime.is_original))
{
- int i;
-
+ const int *index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX);
/* Get the average of all verts with (original index == nr). */
- for (i = 0; i < numVerts; i++) {
- const int *index = dm->getVertData(dm, i, CD_ORIGINDEX);
- if (*index == nr) {
- float co[3];
- dm->getVertCo(dm, i, co);
- add_v3_v3(vec, co);
+ for (int i = 0; i < numVerts; i++) {
+ if (index[i] == nr) {
+ add_v3_v3(vec, me_eval->mvert[i].co);
count++;
}
}
}
else {
if (nr < numVerts) {
- float co[3];
- dm->getVertCo(dm, nr, co);
- add_v3_v3(vec, co);
+ add_v3_v3(vec, me_eval->mvert[nr].co);
count++;
}
}
@@ -1897,7 +2111,9 @@ static void give_parvert(Object *par, int nr, float vec[3])
}
else {
/* use first index if its out of range */
- dm->getVertCo(dm, 0, vec);
+ if (me_eval->totvert) {
+ copy_v3_v3(vec, me_eval->mvert[0].co);
+ }
}
}
else {
@@ -1910,10 +2126,10 @@ static void give_parvert(Object *par, int nr, float vec[3])
ListBase *nurb;
/* Unless there's some weird depsgraph failure the cache should exist. */
- BLI_assert(par->curve_cache != NULL);
+ BLI_assert(par->runtime.curve_cache != NULL);
- if (par->curve_cache->deformed_nurbs.first != NULL) {
- nurb = &par->curve_cache->deformed_nurbs;
+ if (par->runtime.curve_cache->deformed_nurbs.first != NULL) {
+ nurb = &par->runtime.curve_cache->deformed_nurbs;
}
else {
Curve *cu = par->data;
@@ -1924,7 +2140,7 @@ static void give_parvert(Object *par, int nr, float vec[3])
}
else if (par->type == OB_LATTICE) {
Lattice *latt = par->data;
- DispList *dl = par->curve_cache ? BKE_displist_find(&par->curve_cache->disp, DL_VERTS) : NULL;
+ DispList *dl = par->runtime.curve_cache ? BKE_displist_find(&par->runtime.curve_cache->disp, DL_VERTS) : NULL;
float (*co)[3] = dl ? (float (*)[3])dl->verts : NULL;
int tot;
@@ -1969,7 +2185,7 @@ static void ob_parvert3(Object *ob, Object *par, float mat[4][4])
}
-void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float parentmat[4][4])
+void BKE_object_get_parent_matrix(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, float parentmat[4][4])
{
float tmat[4][4];
float vec[3];
@@ -1980,7 +2196,7 @@ void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float p
ok = 0;
if (par->type == OB_CURVE) {
if ((((Curve *)par->data)->flag & CU_PATH) &&
- (ob_parcurve(scene, ob, par, tmat)))
+ (ob_parcurve(depsgraph, scene, ob, par, tmat)))
{
ok = 1;
}
@@ -2016,7 +2232,8 @@ void BKE_object_get_parent_matrix(Scene *scene, Object *ob, Object *par, float p
/**
* \param r_originmat Optional matrix that stores the space the object is in (without its own matrix applied)
*/
-static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4][4], float slowmat[4][4],
+static void solve_parenting(Depsgraph *depsgraph,
+ Scene *scene, Object *ob, Object *par, float obmat[4][4], float slowmat[4][4],
float r_originmat[3][3], const bool set_origin)
{
float totmat[4][4];
@@ -2027,7 +2244,7 @@ static void solve_parenting(Scene *scene, Object *ob, Object *par, float obmat[4
if (ob->partype & PARSLOW) copy_m4_m4(slowmat, obmat);
- BKE_object_get_parent_matrix(scene, ob, par, totmat);
+ BKE_object_get_parent_matrix(depsgraph, scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
@@ -2070,20 +2287,21 @@ static bool where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat
}
/* note, scene is the active scene while actual_scene is the scene the object resides in */
-void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
- RigidBodyWorld *rbw, float r_originmat[3][3])
+void BKE_object_where_is_calc_time_ex(
+ Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime,
+ RigidBodyWorld *rbw, float r_originmat[3][3])
{
if (ob == NULL) return;
/* execute drivers only, as animation has already been done */
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, ctime, ADT_RECALC_DRIVERS);
if (ob->parent) {
Object *par = ob->parent;
float slowmat[4][4];
/* calculate parent matrix */
- solve_parenting(scene, ob, par, ob->obmat, slowmat, r_originmat, true);
+ solve_parenting(depsgraph, scene, ob, par, ob->obmat, slowmat, r_originmat, true);
/* "slow parent" is definitely not threadsafe, and may also give bad results jumping around
* An old-fashioned hack which probably doesn't really cut it anymore
@@ -2105,8 +2323,8 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
/* solve constraints */
if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) {
bConstraintOb *cob;
- cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
- BKE_constraints_solve(&ob->constraints, cob, ctime);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
BKE_constraints_clear_evalob(cob);
}
@@ -2115,16 +2333,16 @@ void BKE_object_where_is_calc_time_ex(Scene *scene, Object *ob, float ctime,
else ob->transflag &= ~OB_NEG_SCALE;
}
-void BKE_object_where_is_calc_time(Scene *scene, Object *ob, float ctime)
+void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *ob, float ctime)
{
- BKE_object_where_is_calc_time_ex(scene, ob, ctime, NULL, NULL);
+ BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, ctime, NULL, NULL);
}
/* get object transformation matrix without recalculating dependencies and
* constraints -- assume dependencies are already solved by depsgraph.
* no changes to object and it's parent would be done.
* used for bundles orientation in 3d space relative to parented blender camera */
-void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4])
+void BKE_object_where_is_calc_mat4(Depsgraph *depsgraph, Scene *scene, Object *ob, float obmat[4][4])
{
if (ob->parent) {
@@ -2132,7 +2350,7 @@ void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4])
Object *par = ob->parent;
- solve_parenting(scene, ob, par, obmat, slowmat, NULL, false);
+ solve_parenting(depsgraph, scene, ob, par, obmat, slowmat, NULL, false);
if (ob->partype & PARSLOW)
where_is_object_parslow(ob, obmat, slowmat);
@@ -2142,52 +2360,69 @@ void BKE_object_where_is_calc_mat4(Scene *scene, Object *ob, float obmat[4][4])
}
}
-void BKE_object_where_is_calc_ex(Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
+void BKE_object_where_is_calc_ex(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, float r_originmat[3][3])
{
- BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), rbw, r_originmat);
+ BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), rbw, r_originmat);
}
-void BKE_object_where_is_calc(Scene *scene, Object *ob)
+void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_object_where_is_calc_time_ex(scene, ob, BKE_scene_frame_get(scene), NULL, NULL);
+ BKE_object_where_is_calc_time_ex(depsgraph, scene, ob, DEG_get_ctime(depsgraph), NULL, NULL);
}
-/* for calculation of the inverse parent transform, only used for editor */
-void BKE_object_workob_calc_parent(Scene *scene, Object *ob, Object *workob)
+/**
+ * For calculation of the inverse parent transform, only used for editor.
+ *
+ * It assumes the object parent is already in the depsgraph.
+ * Otherwise, after changing ob->parent you need to call:
+ * - #DEG_relations_tag_update(bmain);
+ * - #BKE_scene_graph_update_tagged(depsgraph, bmain);
+ */
+void BKE_object_workob_calc_parent(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *workob)
{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
BKE_object_workob_clear(workob);
unit_m4(workob->obmat);
unit_m4(workob->parentinv);
unit_m4(workob->constinv);
- workob->parent = ob->parent;
- workob->trackflag = ob->trackflag;
- workob->upflag = ob->upflag;
+ /* Since this is used while calculating parenting, at this moment ob_eval->parent is still NULL. */
+ workob->parent = DEG_get_evaluated_object(depsgraph, ob->parent);
+
+ workob->trackflag = ob_eval->trackflag;
+ workob->upflag = ob_eval->upflag;
- workob->partype = ob->partype;
- workob->par1 = ob->par1;
- workob->par2 = ob->par2;
- workob->par3 = ob->par3;
+ workob->partype = ob_eval->partype;
+ workob->par1 = ob_eval->par1;
+ workob->par2 = ob_eval->par2;
+ workob->par3 = ob_eval->par3;
- workob->constraints.first = ob->constraints.first;
- workob->constraints.last = ob->constraints.last;
+ workob->constraints = ob_eval->constraints;
- BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr));
+ BLI_strncpy(workob->parsubstr, ob_eval->parsubstr, sizeof(workob->parsubstr));
- BKE_object_where_is_calc(scene, workob);
+ BKE_object_where_is_calc(depsgraph, scene, workob);
}
-/* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
-void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent)
+/**
+ * Applies the global transformation \a mat to the \a ob using a relative parent space if supplied.
+ *
+ * \param mat the global transformation mat that the object should be set object to.
+ * \param parent the parent space in which this object will be set relative to (should probably always be parent_eval).
+ * \param use_compat true to ensure that rotations are set using the min difference between the old and new orientation.
+ */
+void BKE_object_apply_mat4_ex(Object *ob, float mat[4][4], Object *parent, float parentinv[4][4], const bool use_compat)
{
+ /* see BKE_pchan_apply_mat4() for the equivalent 'pchan' function */
+
float rot[3][3];
- if (use_parent && ob->parent) {
+ if (parent != NULL) {
float rmat[4][4], diff_mat[4][4], imat[4][4], parent_mat[4][4];
- BKE_object_get_parent_matrix(NULL, ob, ob->parent, parent_mat);
+ BKE_object_get_parent_matrix(NULL, NULL, ob, parent, parent_mat);
- mul_m4_m4m4(diff_mat, parent_mat, ob->parentinv);
+ mul_m4_m4m4(diff_mat, parent_mat, parentinv);
invert_m4_m4(imat, diff_mat);
mul_m4_m4m4(rmat, imat, mat); /* get the parent relative matrix */
@@ -2209,10 +2444,16 @@ void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, c
/* BKE_object_mat3_to_rot handles delta rotations */
}
+/* XXX: should be removed after COW operators port to use BKE_object_apply_mat4_ex directly */
+void BKE_object_apply_mat4(Object *ob, float mat[4][4], const bool use_compat, const bool use_parent)
+{
+ BKE_object_apply_mat4_ex(ob, mat, use_parent ? ob->parent : NULL, ob->parentinv, use_compat);
+}
+
BoundBox *BKE_boundbox_alloc_unit(void)
{
BoundBox *bb;
- const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {-1.0f, -1.0f, -1.0f};
+ const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
bb = MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
BKE_boundbox_init_from_minmax(bb, min, max);
@@ -2260,20 +2501,29 @@ BoundBox *BKE_object_boundbox_get(Object *ob)
{
BoundBox *bb = NULL;
- if (ob->type == OB_MESH) {
- bb = BKE_mesh_boundbox_get(ob);
- }
- else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
- bb = BKE_curve_boundbox_get(ob);
- }
- else if (ob->type == OB_MBALL) {
- bb = ob->bb;
- }
- else if (ob->type == OB_LATTICE) {
- bb = BKE_lattice_boundbox_get(ob);
- }
- else if (ob->type == OB_ARMATURE) {
- bb = BKE_armature_boundbox_get(ob);
+ switch (ob->type) {
+ case OB_MESH:
+ bb = BKE_mesh_boundbox_get(ob);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ bb = BKE_curve_boundbox_get(ob);
+ break;
+ case OB_MBALL:
+ bb = BKE_mball_boundbox_get(ob);
+ break;
+ case OB_LATTICE:
+ bb = BKE_lattice_boundbox_get(ob);
+ break;
+ case OB_ARMATURE:
+ bb = BKE_armature_boundbox_get(ob);
+ break;
+ case OB_GPENCIL:
+ bb = BKE_gpencil_boundbox_get(ob);
+ break;
+ default:
+ break;
}
return bb;
}
@@ -2288,6 +2538,23 @@ void BKE_object_boundbox_flag(Object *ob, int flag, const bool set)
}
}
+void BKE_object_boundbox_calc_from_mesh(struct Object *ob, struct Mesh *me_eval)
+{
+ float min[3], max[3];
+
+ INIT_MINMAX(min, max);
+
+ BKE_mesh_minmax(me_eval, min, max);
+
+ if (ob->bb == NULL) {
+ ob->bb = MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
+ }
+
+ BKE_boundbox_init_from_minmax(ob->bb, min, max);
+
+ ob->bb->flag &= ~BOUNDBOX_DIRTY;
+}
+
void BKE_object_dimensions_get(Object *ob, float vec[3])
{
BoundBox *bb = NULL;
@@ -2393,7 +2660,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us
float size[3];
copy_v3_v3(size, ob->size);
- if (ob->type == OB_EMPTY) {
+ if ((ob->type == OB_EMPTY) || (ob->type == OB_GPENCIL)) {
mul_v3_fl(size, ob->empty_drawsize);
}
@@ -2417,9 +2684,9 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value)
if (!ob->iuser) {
ob->iuser = MEM_callocN(sizeof(ImageUser), "image user");
ob->iuser->ok = 1;
+ ob->iuser->flag |= IMA_ANIM_ALWAYS;
ob->iuser->frames = 100;
ob->iuser->sfra = 1;
- ob->iuser->fie_ima = 2;
}
}
else {
@@ -2430,9 +2697,7 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value)
}
}
-bool BKE_object_minmax_dupli(
- Main *bmain, Scene *scene,
- Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
+bool BKE_object_minmax_dupli(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_min[3], float r_max[3], const bool use_hidden)
{
bool ok = false;
if ((ob->transflag & OB_DUPLI) == 0) {
@@ -2441,7 +2706,7 @@ bool BKE_object_minmax_dupli(
else {
ListBase *lb;
DupliObject *dob;
- lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob);
+ lb = object_duplilist(depsgraph, scene, ob);
for (dob = lb->first; dob; dob = dob->next) {
if ((use_hidden == false) && (dob->no_draw != 0)) {
/* pass */
@@ -2473,21 +2738,19 @@ void BKE_object_foreach_display_point(
{
float co[3];
- if (ob->derivedFinal) {
- DerivedMesh *dm = ob->derivedFinal;
- MVert *mv = dm->getVertArray(dm);
- int totvert = dm->getNumVerts(dm);
- int i;
-
- for (i = 0; i < totvert; i++, mv++) {
+ if (ob->runtime.mesh_eval) {
+ const Mesh *me = ob->runtime.mesh_eval;
+ const MVert *mv = me->mvert;
+ const int totvert = me->totvert;
+ for (int i = 0; i < totvert; i++, mv++) {
mul_v3_m4v3(co, obmat, mv->co);
func_cb(co, user_data);
}
}
- else if (ob->curve_cache && ob->curve_cache->disp.first) {
+ else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) {
DispList *dl;
- for (dl = ob->curve_cache->disp.first; dl; dl = dl->next) {
+ for (dl = ob->runtime.curve_cache->disp.first; dl; dl = dl->next) {
const float *v3 = dl->verts;
int totvert = dl->nr;
int i;
@@ -2501,33 +2764,20 @@ void BKE_object_foreach_display_point(
}
void BKE_scene_foreach_display_point(
- Main *bmain, Scene *scene, View3D *v3d, const short flag,
+ Depsgraph *depsgraph,
void (*func_cb)(const float[3], void *), void *user_data)
{
- Base *base;
- Object *ob;
-
- for (base = FIRSTBASE; base; base = base->next) {
- if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag & flag) == flag) {
- ob = base->object;
-
- if ((ob->transflag & OB_DUPLI) == 0) {
- BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
- }
- else {
- ListBase *lb;
- DupliObject *dob;
-
- lb = object_duplilist(bmain, bmain->eval_ctx, scene, ob);
- for (dob = lb->first; dob; dob = dob->next) {
- if (dob->no_draw == 0) {
- BKE_object_foreach_display_point(dob->ob, dob->mat, func_cb, user_data);
- }
- }
- free_object_duplilist(lb); /* does restore */
- }
+ DEG_OBJECT_ITER_BEGIN(
+ depsgraph, ob,
+ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI)
+ {
+ if ((ob->base_flag & BASE_SELECTED) != 0) {
+ BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
}
}
+ DEG_OBJECT_ITER_END;
}
/* copied from DNA_object_types.h */
@@ -2541,7 +2791,7 @@ typedef struct ObTfmBack {
float obmat[4][4]; /* final worldspace matrix with constraints & animsys applied */
float parentinv[4][4]; /* inverse result of parent, so that object doesn't 'stick' to parent */
float constinv[4][4]; /* inverse result of constraints. doesn't include effect of parent or object local transform */
- float imat[4][4]; /* inverse matrix of 'obmat' for during render, old game engine, temporally: ipokeys of transform */
+ float imat[4][4]; /* inverse matrix of 'obmat' for during render, temporally: ipokeys of transform */
} ObTfmBack;
void *BKE_object_tfm_backup(Object *ob)
@@ -2598,25 +2848,24 @@ bool BKE_object_parent_loop_check(const Object *par, const Object *ob)
return BKE_object_parent_loop_check(par->parent, ob);
}
-static void object_handle_update_proxy(Main *bmain,
- EvaluationContext *eval_ctx,
+static void object_handle_update_proxy(Depsgraph *depsgraph,
Scene *scene,
Object *object,
const bool do_proxy_update)
{
- /* The case when this is a group proxy, object_update is called in group.c */
+ /* The case when this is a collection proxy, object_update is called in collection.c */
if (object->proxy == NULL) {
return;
}
/* set pointer in library proxy target, for copying, but restore it */
object->proxy->proxy_from = object;
- // printf("set proxy pointer for later group stuff %s\n", ob->id.name);
+ // printf("set proxy pointer for later collection stuff %s\n", ob->id.name);
/* the no-group proxy case, we call update */
if (object->proxy_group == NULL) {
if (do_proxy_update) {
// printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
- BKE_object_handle_update(bmain, eval_ctx, scene, object->proxy);
+ BKE_object_handle_update(depsgraph, scene, object->proxy);
}
}
}
@@ -2629,14 +2878,18 @@ static void object_handle_update_proxy(Main *bmain,
/* the main object update call, for object matrix, constraints, keys and displist (modifiers) */
/* requires flags to be set! */
/* Ideally we shouldn't have to pass the rigid body world, but need bigger restructuring to avoid id */
-void BKE_object_handle_update_ex(Main *bmain,
- EvaluationContext *eval_ctx,
+void BKE_object_handle_update_ex(Depsgraph *depsgraph,
Scene *scene, Object *ob,
RigidBodyWorld *rbw,
const bool do_proxy_update)
{
- if ((ob->recalc & OB_RECALC_ALL) == 0) {
- object_handle_update_proxy(bmain, eval_ctx, scene, ob, do_proxy_update);
+ const ID *object_data = ob->data;
+ const bool recalc_object = (ob->id.recalc & ID_RECALC) != 0;
+ const bool recalc_data =
+ (object_data != NULL) ? ((object_data->recalc & ID_RECALC_ALL) != 0)
+ : 0;
+ if (!recalc_object && ! recalc_data) {
+ object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
return;
}
/* Speed optimization for animation lookups. */
@@ -2646,46 +2899,48 @@ void BKE_object_handle_update_ex(Main *bmain,
BKE_pose_update_constraint_flags(ob->pose);
}
}
- if (ob->recalc & OB_RECALC_DATA) {
+ if (recalc_data) {
if (ob->type == OB_ARMATURE) {
/* this happens for reading old files and to match library armatures
* with poses we do it ahead of BKE_object_where_is_calc to ensure animation
* is evaluated on the rebuilt pose, otherwise we get incorrect poses
* on file load */
- if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC))
- BKE_pose_rebuild(ob, ob->data);
+ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
+ /* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */
+ BKE_pose_rebuild(NULL, ob, ob->data, true);
+ }
}
}
/* XXX new animsys warning: depsgraph tag OB_RECALC_DATA should not skip drivers,
* which is only in BKE_object_where_is_calc now */
/* XXX: should this case be OB_RECALC_OB instead? */
- if (ob->recalc & OB_RECALC_ALL) {
+ if (recalc_object || recalc_data) {
if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
printf("recalcob %s\n", ob->id.name + 2);
}
/* Handle proxy copy for target. */
- if (!BKE_object_eval_proxy_copy(eval_ctx, ob)) {
- BKE_object_where_is_calc_ex(scene, rbw, ob, NULL);
+ if (!BKE_object_eval_proxy_copy(depsgraph, ob)) {
+ BKE_object_where_is_calc_ex(depsgraph, scene, rbw, ob, NULL);
}
}
- if (ob->recalc & OB_RECALC_DATA) {
- BKE_object_handle_data_update(bmain, eval_ctx, scene, ob);
+ if (recalc_data) {
+ BKE_object_handle_data_update(depsgraph, scene, ob);
}
- ob->recalc &= ~OB_RECALC_ALL;
+ ob->id.recalc &= ID_RECALC_ALL;
- object_handle_update_proxy(bmain, eval_ctx, scene, ob, do_proxy_update);
+ object_handle_update_proxy(depsgraph, scene, ob, do_proxy_update);
}
/* WARNING: "scene" here may not be the scene object actually resides in.
* When dealing with background-sets, "scene" is actually the active scene.
* e.g. "scene" <-- set 1 <-- set 2 ("ob" lives here) <-- set 3 <-- ... <-- set n
- * rigid bodies depend on their world so use BKE_object_handle_update_ex() to also pass along the corrent rigid body world
+ * rigid bodies depend on their world so use BKE_object_handle_update_ex() to also pass along the current rigid body world
*/
-void BKE_object_handle_update(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob)
+void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- BKE_object_handle_update_ex(bmain, eval_ctx, scene, ob, NULL, true);
+ BKE_object_handle_update_ex(depsgraph, scene, ob, NULL, true);
}
void BKE_object_sculpt_modifiers_changed(Object *ob)
@@ -2730,14 +2985,7 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
switch (GS(((ID *)ob->data)->name)) {
case ID_ME:
{
- Mesh *me = ob->data;
- if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
- BKE_mesh_texspace_calc(me);
- }
- if (r_texflag) *r_texflag = &me->texflag;
- if (r_loc) *r_loc = me->loc;
- if (r_size) *r_size = me->size;
- if (r_rot) *r_rot = me->rot;
+ BKE_mesh_texspace_get_reference((Mesh *)ob->data, r_texflag, r_loc, r_rot, r_size);
break;
}
case ID_CU:
@@ -2767,6 +3015,68 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
return 1;
}
+/** Get evaluated mesh for given (main, original) object and depsgraph. */
+Mesh *BKE_object_get_evaluated_mesh(const Depsgraph *depsgraph, Object *ob)
+{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ return ob_eval->runtime.mesh_eval;
+}
+
+/* Get object's mesh with all modifiers applied. */
+Mesh *BKE_object_get_final_mesh(Object *object)
+{
+ if (object->runtime.mesh_eval != NULL) {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ BLI_assert(object->runtime.mesh_eval == object->data);
+ BLI_assert((object->runtime.mesh_eval->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) != 0);
+ return object->runtime.mesh_eval;
+ }
+ /* Wasn't evaluated yet. */
+ return object->data;
+}
+
+/* Get mesh which is not affected by modifiers:
+ * - For original objects it will be same as object->data, and it is a mesh
+ * which is in the corresponding bmain.
+ * - For copied-on-write objects it will give pointer to a copied-on-write
+ * mesh which corresponds to original object's mesh.
+ */
+Mesh *BKE_object_get_pre_modified_mesh(Object *object)
+{
+ if (object->runtime.mesh_orig != NULL) {
+ BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE);
+ BLI_assert(object->id.orig_id != NULL);
+ BLI_assert(object->runtime.mesh_orig->id.orig_id == ((Object *)object->id.orig_id)->data);
+ Mesh *result = object->runtime.mesh_orig;
+ BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ BLI_assert((result->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
+ return result;
+ }
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ return object->data;
+}
+
+/* Get a mesh which corresponds to very very original mesh from bmain.
+ * - For original objects it will be object->data.
+ * - For evaluated objects it will be same mesh as corresponding original
+ * object uses as data.
+ */
+Mesh *BKE_object_get_original_mesh(Object *object)
+{
+ Mesh *result = NULL;
+ if (object->id.orig_id == NULL) {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0);
+ result = object->data;
+ }
+ else {
+ BLI_assert((object->id.tag & LIB_TAG_COPIED_ON_WRITE) != 0);
+ result = ((Object *)object->id.orig_id)->data;
+ }
+ BLI_assert(result != NULL);
+ BLI_assert((result->id.tag & (LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT)) == 0);
+ return result;
+}
+
static int pc_cmp(const void *a, const void *b)
{
const LinkData *ad = a, *bd = b;
@@ -2841,7 +3151,7 @@ static KeyBlock *insert_meshkey(Main *bmain, Object *ob, const char *name, const
if (newkey || from_mix == false) {
/* create from mesh */
kb = BKE_keyblock_add_ctime(key, name, false);
- BKE_keyblock_convert_from_mesh(me, kb);
+ BKE_keyblock_convert_from_mesh(me, key, kb);
}
else {
/* copy from current values */
@@ -3269,6 +3579,10 @@ MovieClip *BKE_object_movieclip_get(Scene *scene, Object *ob, bool use_default)
return clip;
}
+void BKE_object_runtime_reset(Object *object)
+{
+ memset(&object->runtime, 0, sizeof(object->runtime));
+}
/*
* Find an associated Armature object
@@ -3304,33 +3618,33 @@ static void obrel_list_add(LinkNode **links, Object *ob)
}
/*
- * Iterates over all objects of the given scene.
+ * Iterates over all objects of the given scene layer.
* Depending on the eObjectSet flag:
* collect either OB_SET_ALL, OB_SET_VISIBLE or OB_SET_SELECTED objects.
* If OB_SET_VISIBLE or OB_SET_SELECTED are collected,
* then also add related objects according to the given includeFilters.
*/
-LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectSet, eObRelationTypes includeFilter)
+LinkNode *BKE_object_relational_superset(struct ViewLayer *view_layer, eObjectSet objectSet, eObRelationTypes includeFilter)
{
LinkNode *links = NULL;
Base *base;
/* Remove markers from all objects */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
/* iterate over all selected and visible objects */
- for (base = scene->base.first; base; base = base->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
if (objectSet == OB_SET_ALL) {
/* as we get all anyways just add it */
Object *ob = base->object;
obrel_list_add(&links, ob);
}
else {
- if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(((View3D *)NULL), scene, base)) ||
- (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, base)))
+ if ((objectSet == OB_SET_SELECTED && TESTBASELIB_BGMODE(base)) ||
+ (objectSet == OB_SET_VISIBLE && BASE_EDITABLE_BGMODE(base)))
{
Object *ob = base->object;
@@ -3359,8 +3673,8 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS
/* child relationship */
if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) {
Base *local_base;
- for (local_base = scene->base.first; local_base; local_base = local_base->next) {
- if (BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, local_base)) {
+ for (local_base = view_layer->object_bases.first; local_base; local_base = local_base->next) {
+ if (BASE_EDITABLE_BGMODE(local_base)) {
Object *child = local_base->object;
if (obrel_list_test(child)) {
@@ -3395,27 +3709,21 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS
*/
struct LinkNode *BKE_object_groups(Main *bmain, Object *ob)
{
- LinkNode *group_linknode = NULL;
- Group *group = NULL;
- while ((group = BKE_group_object_find(bmain, group, ob))) {
- BLI_linklist_prepend(&group_linknode, group);
+ LinkNode *collection_linknode = NULL;
+ Collection *collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, collection, ob))) {
+ BLI_linklist_prepend(&collection_linknode, collection);
}
- return group_linknode;
+ return collection_linknode;
}
-void BKE_object_groups_clear(Main *bmain, Scene *scene, Base *base, Object *object)
+void BKE_object_groups_clear(Main *bmain, Object *ob)
{
- Group *group = NULL;
-
- BLI_assert((base == NULL) || (base->object == object));
-
- if (scene && base == NULL) {
- base = BKE_scene_base_find(scene, object);
- }
-
- while ((group = BKE_group_object_find(bmain, group, base->object))) {
- BKE_group_object_unlink(bmain, group, object, scene, base);
+ Collection *collection = NULL;
+ while ((collection = BKE_collection_object_find(bmain, collection, ob))) {
+ BKE_collection_object_remove(bmain, collection, ob, false);
+ DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE);
}
}
@@ -3439,12 +3747,12 @@ KDTree *BKE_object_as_kdtree(Object *ob, int *r_tot)
Mesh *me = ob->data;
unsigned int i;
- DerivedMesh *dm = ob->derivedDeform ? ob->derivedDeform : ob->derivedFinal;
+ Mesh *me_eval = ob->runtime.mesh_deform_eval ? ob->runtime.mesh_deform_eval : ob->runtime.mesh_deform_eval;
const int *index;
- if (dm && (index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))) {
- MVert *mvert = dm->getVertArray(dm);
- unsigned int totvert = dm->getNumVerts(dm);
+ if (me_eval && (index = CustomData_get_layer(&me_eval->vdata, CD_ORIGINDEX))) {
+ MVert *mvert = me_eval->mvert;
+ uint totvert = me_eval->totvert;
/* tree over-allocs in case where some verts have ORIGINDEX_NONE */
tot = 0;
@@ -3594,12 +3902,80 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
return false;
}
+bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
+{
+ if (BKE_gpencil_modifier_dependsOnTime(md)) {
+ return true;
+ }
+
+ /* Check whether modifier is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name);
+
+ /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
+ if (adt->action) {
+ for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
+ return true;
+ }
+ }
+ }
+
+ /* This here allows modifier properties to get driven and still update properly */
+ for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
+{
+ if (BKE_shaderfx_dependsOnTime(fx)) {
+ return true;
+ }
+
+ /* Check whether effect is animated. */
+ /* TODO (Aligorith): this should be handled as part of build_animdata() */
+ if (ob->adt) {
+ AnimData *adt = ob->adt;
+ FCurve *fcu;
+
+ char pattern[MAX_NAME + 32];
+ BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name);
+
+ /* action - check for F-Curves with paths containing string[' */
+ if (adt->action) {
+ for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ /* This here allows properties to get driven and still update properly */
+ for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) {
+ if (fcu->rna_path && strstr(fcu->rna_path, pattern))
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* set "ignore cache" flag for all caches on this object */
-static void object_cacheIgnoreClear(Main *bmain, Object *ob, int state)
+static void object_cacheIgnoreClear(Object *ob, int state)
{
ListBase pidlist;
PTCacheID *pid;
- BKE_ptcache_ids_from_object(bmain, &pidlist, ob, NULL, 0);
+ BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
for (pid = pidlist.first; pid; pid = pid->next) {
if (pid->cache) {
@@ -3617,10 +3993,8 @@ static void object_cacheIgnoreClear(Main *bmain, Object *ob, int state)
* Avoid calling this in new code unless there is a very good reason for it!
*/
bool BKE_object_modifier_update_subframe(
- Main *bmain, EvaluationContext *eval_ctx,
- Scene *scene, Object *ob, bool update_mesh,
- int parent_recursion, float frame,
- int type)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, bool update_mesh,
+ int parent_recursion, float frame, int type)
{
ModifierData *md = modifiers_findByType(ob, (ModifierType)type);
bConstraint *con;
@@ -3643,8 +4017,8 @@ bool BKE_object_modifier_update_subframe(
if (parent_recursion) {
int recursion = parent_recursion - 1;
bool no_update = false;
- if (ob->parent) no_update |= BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ob->parent, 0, recursion, frame, type);
- if (ob->track) no_update |= BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ob->track, 0, recursion, frame, type);
+ if (ob->parent) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->parent, 0, recursion, frame, type);
+ if (ob->track) no_update |= BKE_object_modifier_update_subframe(depsgraph, scene, ob->track, 0, recursion, frame, type);
/* skip subframe if object is parented
* to vertex of a dynamic paint canvas */
@@ -3661,7 +4035,7 @@ bool BKE_object_modifier_update_subframe(
cti->get_constraint_targets(con, &targets);
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar)
- BKE_object_modifier_update_subframe(bmain, eval_ctx, scene, ct->tar, 0, recursion, frame, type);
+ BKE_object_modifier_update_subframe(depsgraph, scene, ct->tar, 0, recursion, frame, type);
}
/* free temp targets */
if (cti->flush_constraint_targets)
@@ -3671,28 +4045,29 @@ bool BKE_object_modifier_update_subframe(
}
/* was originally OB_RECALC_ALL - TODO - which flags are really needed??? */
- ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
+ /* TODO(sergey): What about animation? */
+ ob->id.recalc |= ID_RECALC_ALL;
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, frame, ADT_RECALC_ANIM);
if (update_mesh) {
/* ignore cache clear during subframe updates
- * to not mess up cache validity */
- object_cacheIgnoreClear(bmain, ob, 1);
- BKE_object_handle_update(bmain, eval_ctx, scene, ob);
- object_cacheIgnoreClear(bmain, ob, 0);
+ * to not mess up cache validity */
+ object_cacheIgnoreClear(ob, 1);
+ BKE_object_handle_update(depsgraph, scene, ob);
+ object_cacheIgnoreClear(ob, 0);
}
else
- BKE_object_where_is_calc_time(scene, ob, frame);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, frame);
/* for curve following objects, parented curve has to be updated too */
if (ob->type == OB_CURVE) {
Curve *cu = ob->data;
- BKE_animsys_evaluate_animdata(scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &cu->id, cu->adt, frame, ADT_RECALC_ANIM);
}
/* and armatures... */
if (ob->type == OB_ARMATURE) {
bArmature *arm = ob->data;
- BKE_animsys_evaluate_animdata(scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
- BKE_pose_where_is(scene, ob);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &arm->id, arm->adt, frame, ADT_RECALC_ANIM);
+ BKE_pose_where_is(depsgraph, scene, ob);
}
return false;
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 47f86c28dfc..70569bfd51b 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -51,7 +51,9 @@
#include "BKE_editmesh.h"
#include "BKE_object_deform.h" /* own include */
#include "BKE_object.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_gpencil.h"
/** \name Misc helpers
* \{ */
@@ -401,10 +403,17 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
*/
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
- if (BKE_object_is_in_editmode_vgroup(ob))
- object_defgroup_remove_edit_mode(ob, defgroup);
- else
- object_defgroup_remove_object_mode(ob, defgroup);
+ if (ob->type == OB_GPENCIL) {
+ BKE_gpencil_vgroup_remove(ob, defgroup);
+ }
+ else {
+ if (BKE_object_is_in_editmode_vgroup(ob))
+ object_defgroup_remove_edit_mode(ob, defgroup);
+ else
+ object_defgroup_remove_object_mode(ob, defgroup);
+
+ BKE_object_batch_cache_dirty_tag(ob);
+ }
}
/**
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index a3fb9981880..d9aa6407474 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -42,26 +42,30 @@
#include "BLI_rand.h"
#include "DNA_anim_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_vfont_types.h"
#include "BKE_animsys.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_depsgraph.h"
+#include "BKE_collection.h"
#include "BKE_font.h"
-#include "BKE_group.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_iterators.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_editmesh.h"
#include "BKE_anim.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
#include "BLI_strict_flags.h"
#include "BLI_hash.h"
@@ -69,16 +73,14 @@
/* Dupli-Geometry */
typedef struct DupliContext {
- EvaluationContext *eval_ctx;
- bool do_update;
- bool animated;
- Group *group; /* XXX child objects are selected from this group if set, could be nicer */
+ Depsgraph *depsgraph;
+ Collection *collection; /* XXX child objects are selected from this group if set, could be nicer */
+ Object *obedit; /* Only to check if the object is in edit-mode. */
- Main *bmain;
Scene *scene;
+ ViewLayer *view_layer;
Object *object;
float space_mat[4][4];
- unsigned int lay;
int persistent_id[MAX_DUPLI_RECUR];
int level;
@@ -98,23 +100,20 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx);
/* create initial context for root object */
static void init_context(
- DupliContext *r_ctx, Main *bmain, EvaluationContext *eval_ctx,
- Scene *scene, Object *ob, float space_mat[4][4], bool update)
+ DupliContext *r_ctx, Depsgraph *depsgraph,
+ Scene *scene, Object *ob, float space_mat[4][4])
{
- r_ctx->eval_ctx = eval_ctx;
- r_ctx->bmain = bmain;
+ r_ctx->depsgraph = depsgraph;
r_ctx->scene = scene;
- /* don't allow BKE_object_handle_update for viewport during render, can crash */
- r_ctx->do_update = update && !(G.is_rendering && eval_ctx->mode != DAG_EVAL_RENDER);
- r_ctx->animated = false;
- r_ctx->group = NULL;
+ r_ctx->view_layer = DEG_get_evaluated_view_layer(depsgraph);
+ r_ctx->collection = NULL;
r_ctx->object = ob;
+ r_ctx->obedit = OBEDIT_FROM_OBACT(ob);
if (space_mat)
copy_m4_m4(r_ctx->space_mat, space_mat);
else
unit_m4(r_ctx->space_mat);
- r_ctx->lay = ob->lay;
r_ctx->level = 0;
r_ctx->gen = get_dupli_generator(r_ctx);
@@ -123,15 +122,13 @@ static void init_context(
}
/* create sub-context for recursive duplis */
-static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index, bool animated)
+static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Object *ob, float mat[4][4], int index)
{
*r_ctx = *ctx;
- r_ctx->animated |= animated; /* object animation makes all children animated */
-
/* XXX annoying, previously was done by passing an ID* argument, this at least is more explicit */
- if (ctx->gen->type == OB_DUPLIGROUP)
- r_ctx->group = ctx->object->dup_group;
+ if (ctx->gen->type == OB_DUPLICOLLECTION)
+ r_ctx->collection = ctx->object->dup_group;
r_ctx->object = ob;
if (mat)
@@ -146,8 +143,7 @@ static void copy_dupli_context(DupliContext *r_ctx, const DupliContext *ctx, Obj
* mat is transform of the object relative to current context (including object obmat)
*/
static DupliObject *make_dupli(const DupliContext *ctx,
- Object *ob, float mat[4][4], int index,
- bool animated, bool hide)
+ Object *ob, float mat[4][4], int index)
{
DupliObject *dob;
int i;
@@ -164,7 +160,6 @@ static DupliObject *make_dupli(const DupliContext *ctx,
dob->ob = ob;
mul_m4_m4m4(dob->mat, (float (*)[4])ctx->space_mat, mat);
dob->type = ctx->gen->type;
- dob->animated = animated || ctx->animated; /* object itself or some parent is animated */
/* set persistent id, which is an array with a persistent index for each level
* (particle number, vertex number, ..). by comparing this we can find the same
@@ -177,8 +172,6 @@ static DupliObject *make_dupli(const DupliContext *ctx,
for (; i < MAX_DUPLI_RECUR; i++)
dob->persistent_id[i] = INT_MAX;
- if (hide)
- dob->no_draw = true;
/* metaballs never draw in duplis, they are instead merged into one by the basis
* mball outside of the group. this does mean that if that mball is not in the
* scene, they will not show up at all, limitation that should be solved once. */
@@ -208,12 +201,12 @@ static DupliObject *make_dupli(const DupliContext *ctx,
/* recursive dupli objects
* space_mat is the local dupli space (excluding dupli object obmat!)
*/
-static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index, bool animated)
+static void make_recursive_duplis(const DupliContext *ctx, Object *ob, float space_mat[4][4], int index)
{
- /* simple preventing of too deep nested groups with MAX_DUPLI_RECUR */
+ /* simple preventing of too deep nested collections with MAX_DUPLI_RECUR */
if (ctx->level < MAX_DUPLI_RECUR) {
DupliContext rctx;
- copy_dupli_context(&rctx, ctx, ob, space_mat, index, animated);
+ copy_dupli_context(&rctx, ctx, ob, space_mat, index);
if (rctx.gen) {
rctx.gen->make_duplis(&rctx);
}
@@ -235,45 +228,40 @@ static bool is_child(const Object *ob, const Object *parent)
return false;
}
-/* create duplis from every child in scene or group */
+/* create duplis from every child in scene or collection */
static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChildDuplisFunc make_child_duplis_cb)
{
Object *parent = ctx->object;
- Object *obedit = ctx->scene->obedit;
-
- if (ctx->group) {
- unsigned int lay = ctx->group->layer;
- int groupid = 0;
- GroupObject *go;
- for (go = ctx->group->gobject.first; go; go = go->next, groupid++) {
- Object *ob = go->ob;
- if ((ob->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ if (ctx->collection) {
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(ctx->collection, ob, mode)
+ {
+ if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, groupid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, _base_id);
/* mballs have a different dupli handling */
- if (ob->type != OB_MBALL)
+ if (ob->type != OB_MBALL) {
ob->flag |= OB_DONE; /* doesn't render */
-
+ }
make_child_duplis_cb(&pctx, userdata, ob);
}
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
else {
- unsigned int lay = ctx->scene->lay;
int baseid = 0;
- Base *base;
- for (base = ctx->scene->base.first; base; base = base->next, baseid++) {
+ ViewLayer *view_layer = ctx->view_layer;
+ for (Base *base = view_layer->object_bases.first; base; base = base->next, baseid++) {
Object *ob = base->object;
-
- if ((base->lay & lay) && ob != obedit && is_child(ob, parent)) {
+ if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, baseid);
/* mballs have a different dupli handling */
if (ob->type != OB_MBALL)
- ob->flag |= OB_DONE; /* doesnt render */
+ ob->flag |= OB_DONE; /* doesn't render */
make_child_duplis_cb(&pctx, userdata, ob);
}
@@ -284,77 +272,49 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
/*---- Implementations ----*/
-/* OB_DUPLIGROUP */
-static void make_duplis_group(const DupliContext *ctx)
+/* OB_DUPLICOLLECTION */
+static void make_duplis_collection(const DupliContext *ctx)
{
- bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
Object *ob = ctx->object;
- Group *group;
- GroupObject *go;
- float group_mat[4][4];
- int id;
- bool animated, hide;
+ Collection *collection;
+ float collection_mat[4][4];
if (ob->dup_group == NULL) return;
- group = ob->dup_group;
+ collection = ob->dup_group;
- /* combine group offset and obmat */
- unit_m4(group_mat);
- sub_v3_v3(group_mat[3], group->dupli_ofs);
- mul_m4_m4m4(group_mat, ob->obmat, group_mat);
+ /* combine collection offset and obmat */
+ unit_m4(collection_mat);
+ sub_v3_v3(collection_mat[3], collection->dupli_ofs);
+ mul_m4_m4m4(collection_mat, ob->obmat, collection_mat);
/* don't access 'ob->obmat' from now on. */
- /* handles animated groups */
-
- /* we need to check update for objects that are not in scene... */
- if (ctx->do_update) {
- /* note: update is optional because we don't always need object
- * transformations to be correct. Also fixes bug [#29616]. */
- BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, ctx->scene, ob, group);
- }
-
- animated = BKE_group_is_animated(group, ob);
-
- for (go = group->gobject.first, id = 0; go; go = go->next, id++) {
- /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
- if (go->ob != ob) {
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(collection, cob, mode)
+ {
+ if (cob != ob) {
float mat[4][4];
- /* Special case for instancing dupli-groups, see: T40051
- * this object may be instanced via dupli-verts/faces, in this case we don't want to render
- * (blender convention), but _do_ show in the viewport.
- *
- * Regular objects work fine but not if we're instancing dupli-groups,
- * because the rules for rendering aren't applied to objects they instance.
- * We could recursively pass down the 'hide' flag instead, but that seems unnecessary.
- */
- if (for_render && go->ob->parent && go->ob->parent->transflag & (OB_DUPLIVERTS | OB_DUPLIFACES)) {
- continue;
- }
-
- /* group dupli offset, should apply after everything else */
- mul_m4_m4m4(mat, group_mat, go->ob->obmat);
-
- /* check the group instance and object layers match, also that the object visible flags are ok. */
- hide = (go->ob->lay & group->layer) == 0 ||
- (for_render ? go->ob->restrictflag & OB_RESTRICT_RENDER : go->ob->restrictflag & OB_RESTRICT_VIEW);
+ /* collection dupli offset, should apply after everything else */
+ mul_m4_m4m4(mat, collection_mat, cob->obmat);
- make_dupli(ctx, go->ob, mat, id, animated, hide);
+ make_dupli(ctx, cob, mat, _base_id);
/* recursion */
- make_recursive_duplis(ctx, go->ob, group_mat, id, animated);
+ make_recursive_duplis(ctx, cob, collection_mat, _base_id);
}
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
-static const DupliGenerator gen_dupli_group = {
- OB_DUPLIGROUP, /* type */
- make_duplis_group /* make_duplis */
+static const DupliGenerator gen_dupli_collection = {
+ OB_DUPLICOLLECTION, /* type */
+ make_duplis_collection /* make_duplis */
};
/* OB_DUPLIFRAMES */
static void make_duplis_frames(const DupliContext *ctx)
{
+ Depsgraph *depsgraph = ctx->depsgraph;
Scene *scene = ctx->scene;
Object *ob = ctx->object;
extern int enable_cu_speed; /* object.c */
@@ -362,8 +322,8 @@ static void make_duplis_frames(const DupliContext *ctx)
int cfrao = scene->r.cfra;
int dupend = ob->dupend;
- /* dupliframes not supported inside groups */
- if (ctx->group)
+ /* dupliframes not supported inside collections */
+ if (ctx->collection)
return;
/* if we don't have any data/settings which will lead to object movement,
* don't waste time trying, as it will all look the same...
@@ -381,10 +341,6 @@ static void make_duplis_frames(const DupliContext *ctx)
/* duplicate over the required range */
if (ob->transflag & OB_DUPLINOSPEED) enable_cu_speed = 0;
- /* special flag to avoid setting recalc flags to notify the depsgraph of
- * updates, as this is not a permanent change to the object */
- ob->id.recalc |= ID_RECALC_SKIP_ANIM_TAG;
-
for (scene->r.cfra = ob->dupsta; scene->r.cfra <= dupend; scene->r.cfra++) {
int ok = 1;
@@ -402,10 +358,11 @@ static void make_duplis_frames(const DupliContext *ctx)
* and/or other objects which may affect this object's transforms are not updated either.
* However, this has always been the way that this worked (i.e. pre 2.5), so I guess that it'll be fine!
*/
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */
- BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra);
+ /* ob-eval will do drivers, so we don't need to do them */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra);
- make_dupli(ctx, ob, ob->obmat, scene->r.cfra, false, false);
+ make_dupli(ctx, ob, ob->obmat, scene->r.cfra);
}
}
@@ -416,8 +373,9 @@ static void make_duplis_frames(const DupliContext *ctx)
*/
scene->r.cfra = cfrao;
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */
- BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra);
+ /* ob-eval will do drivers, so we don't need to do them */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, (float)scene->r.cfra);
/* but, to make sure unkeyed object transforms are still sane,
* let's copy object's original data back over
@@ -432,7 +390,7 @@ static const DupliGenerator gen_dupli_frames = {
/* OB_DUPLIVERTS */
typedef struct VertexDupliData {
- DerivedMesh *dm;
+ Mesh *me_eval;
BMEditMesh *edit_btmesh;
int totvert;
float (*orco)[3];
@@ -490,56 +448,34 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3],
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false);
+ dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index);
if (vdd->orco)
copy_v3_v3(dob->orco, vdd->orco[index]);
/* recursion */
- make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index, false);
+ make_recursive_duplis(vdd->ctx, vdd->inst_ob, space_mat, index);
}
static void make_child_duplis_verts(const DupliContext *ctx, void *userdata, Object *child)
{
VertexDupliData *vdd = userdata;
- DerivedMesh *dm = vdd->dm;
+ Mesh *me_eval = vdd->me_eval;
vdd->inst_ob = child;
invert_m4_m4(child->imat, child->obmat);
/* relative transform from parent to child space */
mul_m4_m4m4(vdd->child_imat, child->imat, ctx->object->obmat);
- if (vdd->edit_btmesh) {
- dm->foreachMappedVert(dm, vertex_dupli__mapFunc, vdd,
- vdd->use_rotation ? DM_FOREACH_USE_NORMAL : 0);
- }
- else {
- int a, totvert = vdd->totvert;
- float vec[3], no[3];
-
- if (vdd->use_rotation) {
- for (a = 0; a < totvert; a++) {
- dm->getVertCo(dm, a, vec);
- dm->getVertNo(dm, a, no);
-
- vertex_dupli__mapFunc(vdd, a, vec, no, NULL);
- }
- }
- else {
- for (a = 0; a < totvert; a++) {
- dm->getVertCo(dm, a, vec);
-
- vertex_dupli__mapFunc(vdd, a, vec, NULL, NULL);
- }
- }
- }
+ BKE_mesh_foreach_mapped_vert(me_eval, vertex_dupli__mapFunc, vdd,
+ vdd->use_rotation ? MESH_FOREACH_USE_NORMAL : 0);
}
static void make_duplis_verts(const DupliContext *ctx)
{
Scene *scene = ctx->scene;
Object *parent = ctx->object;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
VertexDupliData vdd;
vdd.ctx = ctx;
@@ -547,32 +483,31 @@ static void make_duplis_verts(const DupliContext *ctx)
/* gather mesh info */
{
- Mesh *me = parent->data;
- BMEditMesh *em = BKE_editmesh_from_object(parent);
CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH);
+ vdd.edit_btmesh = BKE_editmesh_from_object(parent);
- if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
- vdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
- }
- else if (em) {
- vdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
+ /* We do not need any render-smecific handling anymore, depsgraph takes care of that. */
+ if (vdd.edit_btmesh != NULL) {
+ /* XXX TODO replace with equivalent of editbmesh_get_eval_cage when available. */
+ vdd.me_eval = mesh_get_eval_deform(ctx->depsgraph, scene, parent, dm_mask);
}
else {
- vdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ vdd.me_eval = mesh_get_eval_final(ctx->depsgraph, scene, parent, dm_mask);
}
- vdd.edit_btmesh = me->edit_btmesh;
- if (use_texcoords)
- vdd.orco = vdd.dm->getVertDataArray(vdd.dm, CD_ORCO);
- else
+ if (use_texcoords) {
+ vdd.orco = CustomData_get_layer(&vdd.me_eval->vdata, CD_ORCO);
+ }
+ else {
vdd.orco = NULL;
+ }
- vdd.totvert = vdd.dm->getNumVerts(vdd.dm);
+ vdd.totvert = vdd.me_eval->totvert;
}
make_child_duplis(ctx, &vdd, make_child_duplis_verts);
- vdd.dm->release(vdd.dm);
+ vdd.me_eval = NULL;
}
static const DupliGenerator gen_dupli_verts = {
@@ -626,8 +561,8 @@ static void make_duplis_font(const DupliContext *ctx)
const wchar_t *text = NULL;
bool text_free = false;
- /* font dupliverts not supported inside groups */
- if (ctx->group)
+ /* font dupliverts not supported inside collections */
+ if (ctx->collection)
return;
copy_m4_m4(pmat, par->obmat);
@@ -655,7 +590,9 @@ static void make_duplis_font(const DupliContext *ctx)
/* advance matching BLI_strncpy_wchar_from_utf8 */
for (a = 0; a < text_len; a++, ct++) {
- ob = find_family_object(ctx->bmain, cu->family, family_len, (unsigned int)text[a], family_gh);
+ /* XXX That G.main is *really* ugly, but not sure what to do here...
+ * Definitively don't think it would be safe to put back Main *bmain pointer in DupliContext as done in 2.7x? */
+ ob = find_family_object(G.main, cu->family, family_len, (unsigned int)text[a], family_gh);
if (ob) {
vec[0] = fsize * (ct->xof - xof);
vec[1] = fsize * (ct->yof - yof);
@@ -675,7 +612,7 @@ static void make_duplis_font(const DupliContext *ctx)
copy_v3_v3(obmat[3], vec);
- make_dupli(ctx, ob, obmat, a, false, false);
+ make_dupli(ctx, ob, obmat, a);
}
}
@@ -695,7 +632,7 @@ static const DupliGenerator gen_dupli_verts_font = {
/* OB_DUPLIFACES */
typedef struct FaceDupliData {
- DerivedMesh *dm;
+ Mesh *me_eval;
int totface;
MPoly *mpoly;
MLoop *mloop;
@@ -743,7 +680,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
float (*orco)[3] = fdd->orco;
MLoopUV *mloopuv = fdd->mloopuv;
int a, totface = fdd->totface;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
float child_imat[4][4];
DupliObject *dob;
@@ -781,7 +718,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- dob = make_dupli(ctx, inst_ob, obmat, a, false, false);
+ dob = make_dupli(ctx, inst_ob, obmat, a);
if (use_texcoords) {
float w = 1.0f / (float)mp->totloop;
@@ -801,7 +738,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
}
/* recursion */
- make_recursive_duplis(ctx, inst_ob, space_mat, a, false);
+ make_recursive_duplis(ctx, inst_ob, space_mat, a);
}
}
@@ -809,7 +746,7 @@ static void make_duplis_faces(const DupliContext *ctx)
{
Scene *scene = ctx->scene;
Object *parent = ctx->object;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ bool use_texcoords = (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER);
FaceDupliData fdd;
fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0);
@@ -819,36 +756,34 @@ static void make_duplis_faces(const DupliContext *ctx)
BMEditMesh *em = BKE_editmesh_from_object(parent);
CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH);
- if (ctx->eval_ctx->mode == DAG_EVAL_RENDER) {
- fdd.dm = mesh_create_derived_render(scene, parent, dm_mask);
- }
- else if (em) {
- fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
+ /* We do not need any render-smecific handling anymore, depsgraph takes care of that. */
+ if (em != NULL) {
+ /* XXX TODO replace with equivalent of editbmesh_get_eval_cage when available. */
+ fdd.me_eval = mesh_get_eval_deform(ctx->depsgraph, scene, parent, dm_mask);
}
else {
- fdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
+ fdd.me_eval = mesh_get_eval_final(ctx->depsgraph, scene, parent, dm_mask);
}
if (use_texcoords) {
- CustomData *ml_data = fdd.dm->getLoopDataLayout(fdd.dm);
- const int uv_idx = CustomData_get_render_layer(ml_data, CD_MLOOPUV);
- fdd.orco = fdd.dm->getVertDataArray(fdd.dm, CD_ORCO);
- fdd.mloopuv = CustomData_get_layer_n(ml_data, CD_MLOOPUV, uv_idx);
+ fdd.orco = CustomData_get_layer(&fdd.me_eval->vdata, CD_ORCO);
+ const int uv_idx = CustomData_get_render_layer(&fdd.me_eval->ldata, CD_MLOOPUV);
+ fdd.mloopuv = CustomData_get_layer_n(&fdd.me_eval->ldata, CD_MLOOPUV, uv_idx);
}
else {
fdd.orco = NULL;
fdd.mloopuv = NULL;
}
- fdd.totface = fdd.dm->getNumPolys(fdd.dm);
- fdd.mpoly = fdd.dm->getPolyArray(fdd.dm);
- fdd.mloop = fdd.dm->getLoopArray(fdd.dm);
- fdd.mvert = fdd.dm->getVertArray(fdd.dm);
+ fdd.totface = fdd.me_eval->totpoly;
+ fdd.mpoly = fdd.me_eval->mpoly;
+ fdd.mloop = fdd.me_eval->mloop;
+ fdd.mvert = fdd.me_eval->mvert;
}
make_child_duplis(ctx, &fdd, make_child_duplis_faces);
- fdd.dm->release(fdd.dm);
+ fdd.me_eval = NULL;
}
static const DupliGenerator gen_dupli_faces = {
@@ -861,10 +796,10 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
{
Scene *scene = ctx->scene;
Object *par = ctx->object;
- bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER;
- bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
+ eEvaluationMode mode = DEG_get_mode(ctx->depsgraph);
+ bool for_render = mode == DAG_EVAL_RENDER;
+ bool use_texcoords = for_render;
- GroupObject *go;
Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL;
DupliObject *dob;
ParticleDupliWeight *dw;
@@ -877,8 +812,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0;
float (*obmat)[4];
int a, b, hair = 0;
- int totpart, totchild, totgroup = 0 /*, pa_num */;
- const bool dupli_type_hack = !BKE_scene_use_new_shading_nodes(scene);
+ int totpart, totchild;
int no_draw_flag = PARS_UNEXIST;
@@ -889,21 +823,20 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part == NULL)
return;
- if (!psys_check_enabled(par, psys, (ctx->eval_ctx->mode == DAG_EVAL_RENDER)))
+ if (!psys_check_enabled(par, psys, for_render))
return;
if (!for_render)
no_draw_flag |= PARS_NO_DISP;
- ctime = BKE_scene_frame_get(scene); /* NOTE: in old animsys, used parent object's timeoffset... */
+ ctime = DEG_get_ctime(ctx->depsgraph); /* NOTE: in old animsys, used parent object's timeoffset... */
totpart = psys->totpart;
totchild = psys->totchild;
- BLI_srandom((unsigned int)(31415926 + psys->seed));
-
- if ((psys->renderdata || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
+ if ((for_render || part->draw_as == PART_DRAW_REND) && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
ParticleSimulationData sim = {NULL};
+ sim.depsgraph = ctx->depsgraph;
sim.scene = scene;
sim.ob = par;
sim.psys = psys;
@@ -917,10 +850,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
return;
}
else { /*PART_DRAW_GR */
- if (part->dup_group == NULL || BLI_listbase_is_empty(&part->dup_group->gobject))
+ if (part->dup_group == NULL)
+ return;
+
+ const ListBase dup_collection_objects = BKE_collection_object_cache_get(part->dup_group);
+ if (BLI_listbase_is_empty(&dup_collection_objects))
return;
- if (BLI_findptr(&part->dup_group->gobject, par, offsetof(GroupObject, ob))) {
+ if (BLI_findptr(&dup_collection_objects, par, offsetof(Base, object))) {
return;
}
}
@@ -937,46 +874,67 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
totpart = psys->totcached;
}
- psys_check_group_weights(part);
+ RNG *rng = BLI_rng_new_srandom(31415926u + (unsigned int)psys->seed);
psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
/* gather list of objects or single object */
- if (part->ren_as == PART_DRAW_GR) {
- if (ctx->do_update) {
- BKE_group_handle_recalc_and_update(ctx->bmain, ctx->eval_ctx, scene, par, part->dup_group);
- }
+ int totcollection = 0;
+ if (part->ren_as == PART_DRAW_GR) {
if (part->draw & PART_DRAW_COUNT_GR) {
- for (dw = part->dupliweights.first; dw; dw = dw->next)
- totgroup += dw->count;
+ psys_find_group_weights(part);
+
+ for (dw = part->dupliweights.first; dw; dw = dw->next) {
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ if (dw->ob == object) {
+ totcollection += dw->count;
+ break;
+ }
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
+ }
}
else {
- for (go = part->dup_group->gobject.first; go; go = go->next)
- totgroup++;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ (void) object;
+ totcollection++;
+ }
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
/* we also copy the actual objects to restore afterwards, since
* BKE_object_where_is_calc_time will change the object which breaks transform */
- oblist = MEM_callocN((size_t)totgroup * sizeof(Object *), "dupgroup object list");
- obcopylist = MEM_callocN((size_t)totgroup * sizeof(Object), "dupgroup copy list");
-
- if (part->draw & PART_DRAW_COUNT_GR && totgroup) {
- dw = part->dupliweights.first;
+ oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list");
+ obcopylist = MEM_callocN((size_t)totcollection * sizeof(Object), "dupcollection copy list");
- for (a = 0; a < totgroup; dw = dw->next) {
- for (b = 0; b < dw->count; b++, a++) {
- oblist[a] = dw->ob;
- obcopylist[a] = *dw->ob;
+ if (part->draw & PART_DRAW_COUNT_GR) {
+ a = 0;
+ for (dw = part->dupliweights.first; dw; dw = dw->next) {
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ if (dw->ob == object) {
+ for (b = 0; b < dw->count; b++, a++) {
+ oblist[a] = dw->ob;
+ obcopylist[a] = *dw->ob;
+ }
+ break;
+ }
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
}
else {
- go = part->dup_group->gobject.first;
- for (a = 0; a < totgroup; a++, go = go->next) {
- oblist[a] = go->ob;
- obcopylist[a] = *go->ob;
+ a = 0;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
+ oblist[a] = object;
+ obcopylist[a] = *object;
+ a++;
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
}
else {
@@ -1018,14 +976,14 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part->ren_as == PART_DRAW_GR) {
/* prevent divide by zero below [#28336] */
- if (totgroup == 0)
+ if (totcollection == 0)
continue;
- /* for groups, pick the object based on settings */
+ /* for collections, pick the object based on settings */
if (part->draw & PART_DRAW_RAND_GR)
- b = BLI_rand() % totgroup;
+ b = BLI_rng_get_int(rng) % totcollection;
else
- b = a % totgroup;
+ b = a % totcollection;
ob = oblist[b];
obmat = oblist[b]->obmat;
@@ -1065,27 +1023,37 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
if (part->ren_as == PART_DRAW_GR && psys->part->draw & PART_DRAW_WHOLE_GR) {
- for (go = part->dup_group->gobject.first, b = 0; go; go = go->next, b++) {
-
+ b = 0;
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
+ {
copy_m4_m4(tmat, oblist[b]->obmat);
+
/* apply particle scale */
mul_mat3_m4_fl(tmat, size * scale);
mul_v3_fl(tmat[3], size * scale);
- /* group dupli offset, should apply after everything else */
- if (!is_zero_v3(part->dup_group->dupli_ofs))
+
+ /* collection dupli offset, should apply after everything else */
+ if (!is_zero_v3(part->dup_group->dupli_ofs)) {
sub_v3_v3(tmat[3], part->dup_group->dupli_ofs);
+ }
+
/* individual particle transform */
mul_m4_m4m4(mat, pamat, tmat);
- dob = make_dupli(ctx, go->ob, mat, a, false, false);
+ dob = make_dupli(ctx, object, mat, a);
dob->particle_system = psys;
- if (use_texcoords)
+
+ if (use_texcoords) {
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
+ }
+
+ b++;
}
+ FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
else {
/* to give ipos in object correct offset */
- BKE_object_where_is_calc_time(scene, ob, ctime - pa_time);
+ BKE_object_where_is_calc_time(ctx->depsgraph, scene, ob, ctime - pa_time);
copy_v3_v3(vec, obmat[3]);
obmat[3][0] = obmat[3][1] = obmat[3][2] = 0.0f;
@@ -1126,24 +1094,22 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
if (part->draw & PART_DRAW_GLOBAL_OB)
add_v3_v3v3(mat[3], mat[3], vec);
- dob = make_dupli(ctx, ob, mat, a, false, false);
+ dob = make_dupli(ctx, ob, mat, a);
dob->particle_system = psys;
if (use_texcoords)
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
- /* XXX blender internal needs this to be set to dupligroup to render
- * groups correctly, but we don't want this hack for cycles */
- if (dupli_type_hack && ctx->group)
- dob->type = OB_DUPLIGROUP;
}
}
/* restore objects since they were changed in BKE_object_where_is_calc_time */
if (part->ren_as == PART_DRAW_GR) {
- for (a = 0; a < totgroup; a++)
+ for (a = 0; a < totcollection; a++)
*(oblist[a]) = obcopylist[a];
}
else
*ob = obcopy;
+
+ BLI_rng_free(rng);
}
/* clean up */
@@ -1167,7 +1133,7 @@ static void make_duplis_particles(const DupliContext *ctx)
for (psys = ctx->object->particlesystem.first, psysid = 0; psys; psys = psys->next, psysid++) {
/* particles create one more level for persistent psys index */
DupliContext pctx;
- copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid, false);
+ copy_dupli_context(&pctx, ctx, ctx->object, NULL, psysid);
make_duplis_particle_system(&pctx, psys);
}
}
@@ -1189,7 +1155,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
return NULL;
/* Should the dupli's be generated for this object? - Respect restrict flags */
- if (ctx->eval_ctx->mode == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
+ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
return NULL;
if (transflag & OB_DUPLIPARTS) {
@@ -1210,8 +1176,8 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
else if (transflag & OB_DUPLIFRAMES) {
return &gen_dupli_frames;
}
- else if (transflag & OB_DUPLIGROUP) {
- return &gen_dupli_group;
+ else if (transflag & OB_DUPLICOLLECTION) {
+ return &gen_dupli_collection;
}
return NULL;
@@ -1221,11 +1187,11 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
/* ---- ListBase dupli container implementation ---- */
/* Returns a list of DupliObject */
-ListBase *object_duplilist_ex(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, bool update)
+ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
ListBase *duplilist = MEM_callocN(sizeof(ListBase), "duplilist");
DupliContext ctx;
- init_context(&ctx, bmain, eval_ctx, scene, ob, NULL, update);
+ init_context(&ctx, depsgraph, sce, ob, NULL);
if (ctx.gen) {
ctx.duplilist = duplilist;
ctx.gen->make_duplis(&ctx);
@@ -1234,13 +1200,6 @@ ListBase *object_duplilist_ex(Main *bmain, EvaluationContext *eval_ctx, Scene *s
return duplilist;
}
-/* note: previously updating was always done, this is why it defaults to be on
- * but there are likely places it can be called without updating */
-ListBase *object_duplilist(Main *bmain, EvaluationContext *eval_ctx, Scene *sce, Object *ob)
-{
- return object_duplilist_ex(bmain, eval_ctx, sce, ob, true);
-}
-
void free_object_duplilist(ListBase *lb)
{
BLI_freelistN(lb);
@@ -1276,59 +1235,3 @@ int count_duplilist(Object *ob)
}
return 1;
}
-
-DupliApplyData *duplilist_apply(Object *ob, Scene *scene, ListBase *duplilist)
-{
- DupliApplyData *apply_data = NULL;
- int num_objects = BLI_listbase_count(duplilist);
-
- if (num_objects > 0) {
- DupliObject *dob;
- int i;
- apply_data = MEM_mallocN(sizeof(DupliApplyData), "DupliObject apply data");
- apply_data->num_objects = num_objects;
- apply_data->extra = MEM_mallocN(sizeof(DupliExtraData) * (size_t) num_objects,
- "DupliObject apply extra data");
-
- for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
- /* make sure derivedmesh is calculated once, before drawing */
- if (scene && !(dob->ob->transflag & OB_DUPLICALCDERIVED) && dob->ob->type == OB_MESH) {
- mesh_get_derived_final(scene, dob->ob, scene->customdata_mask);
- dob->ob->transflag |= OB_DUPLICALCDERIVED;
- }
- }
-
- for (dob = duplilist->first, i = 0; dob; dob = dob->next, ++i) {
- /* copy obmat from duplis */
- copy_m4_m4(apply_data->extra[i].obmat, dob->ob->obmat);
- copy_m4_m4(dob->ob->obmat, dob->mat);
-
- /* copy layers from the main duplicator object */
- apply_data->extra[i].lay = dob->ob->lay;
- dob->ob->lay = ob->lay;
- }
- }
- return apply_data;
-}
-
-void duplilist_restore(ListBase *duplilist, DupliApplyData *apply_data)
-{
- DupliObject *dob;
- int i;
- /* Restore object matrices.
- * NOTE: this has to happen in reverse order, since nested
- * dupli objects can repeatedly override the obmat.
- */
- for (dob = duplilist->last, i = apply_data->num_objects - 1; dob; dob = dob->prev, --i) {
- copy_m4_m4(dob->ob->obmat, apply_data->extra[i].obmat);
- dob->ob->transflag &= ~OB_DUPLICALCDERIVED;
-
- dob->ob->lay = apply_data->extra[i].lay;
- }
-}
-
-void duplilist_free_apply_data(DupliApplyData *apply_data)
-{
- MEM_freeN(apply_data->extra);
- MEM_freeN(apply_data);
-}
diff --git a/source/blender/blenkernel/intern/object_facemap.c b/source/blender/blenkernel/intern/object_facemap.c
new file mode 100644
index 00000000000..ef254864d2e
--- /dev/null
+++ b/source/blender/blenkernel/intern/object_facemap.c
@@ -0,0 +1,257 @@
+
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/object_facemap.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_listbase.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_object.h"
+#include "BKE_object_facemap.h" /* own include */
+#include "BKE_object_deform.h"
+
+#include "BLT_translation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+static bool fmap_unique_check(void *arg, const char *name)
+{
+ struct {Object *ob; void *fm; } *data = arg;
+
+ bFaceMap *fmap;
+
+ for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) {
+ if (data->fm != fmap) {
+ if (!strcmp(fmap->name, name)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bFaceMap *fmap_duplicate(bFaceMap *infmap)
+{
+ bFaceMap *outfmap;
+
+ if (!infmap)
+ return NULL;
+
+ outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap");
+
+ /* For now, just copy everything over. */
+ memcpy(outfmap, infmap, sizeof(bFaceMap));
+
+ outfmap->next = outfmap->prev = NULL;
+
+ return outfmap;
+}
+
+void BKE_object_facemap_copy_list(ListBase *outbase, const ListBase *inbase)
+{
+ bFaceMap *fmap, *fmapn;
+
+ BLI_listbase_clear(outbase);
+
+ for (fmap = inbase->first; fmap; fmap = fmap->next) {
+ fmapn = fmap_duplicate(fmap);
+ BLI_addtail(outbase, fmapn);
+ }
+}
+
+void BKE_object_facemap_unique_name(Object *ob, bFaceMap *fmap)
+{
+ struct {Object *ob; void *fmap; } data;
+ data.ob = ob;
+ data.fmap = fmap;
+
+ BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name));
+}
+
+bFaceMap *BKE_object_facemap_add_name(Object *ob, const char *name)
+{
+ bFaceMap *fmap;
+
+ if (!ob || ob->type != OB_MESH)
+ return NULL;
+
+ fmap = MEM_callocN(sizeof(bFaceMap), __func__);
+
+ BLI_strncpy(fmap->name, name, sizeof(fmap->name));
+
+ BLI_addtail(&ob->fmaps, fmap);
+
+ ob->actfmap = BLI_listbase_count(&ob->fmaps);
+
+ BKE_object_facemap_unique_name(ob, fmap);
+
+ return fmap;
+}
+
+bFaceMap *BKE_object_facemap_add(Object *ob)
+{
+ return BKE_object_facemap_add_name(ob, DATA_("FaceMap"));
+}
+
+
+static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge)
+{
+ const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (me->edit_btmesh) {
+ BMEditMesh *em = me->edit_btmesh;
+ const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
+
+ if (cd_fmap_offset != -1) {
+ BMFace *efa;
+ BMIter iter;
+ int *map;
+
+ if (purge) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (map) {
+ if (*map == fmap_nr)
+ *map = -1;
+ else if (*map > fmap_nr)
+ *map -= 1;
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
+
+ if (map && *map == fmap_nr && (!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
+ *map = -1;
+ }
+ }
+ }
+ }
+
+ if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
+ ob->actfmap--;
+
+ BLI_remlink(&ob->fmaps, fmap);
+ MEM_freeN(fmap);
+ }
+ }
+}
+
+static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge)
+{
+ const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
+ int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
+ int i;
+
+ if (map) {
+ for (i = 0; i < me->totpoly; i++) {
+ if (map[i] == fmap_nr)
+ map[i] = -1;
+ else if (purge && map[i] > fmap_nr)
+ map[i]--;
+ }
+ }
+ }
+
+ if (ob->actfmap == BLI_listbase_count(&ob->fmaps))
+ ob->actfmap--;
+
+ BLI_remlink(&ob->fmaps, fmap);
+ MEM_freeN(fmap);
+ }
+}
+
+static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge)
+{
+ if (is_edit_mode)
+ object_fmap_remove_edit_mode(ob, fmap, false, purge);
+ else
+ object_fmap_remove_object_mode(ob, fmap, purge);
+}
+
+void BKE_object_facemap_remove(Object *ob, bFaceMap *fmap)
+{
+ fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true);
+}
+
+void BKE_object_facemap_clear(Object *ob)
+{
+ bFaceMap *fmap = (bFaceMap *)ob->fmaps.first;
+
+ if (fmap) {
+ const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
+
+ while (fmap) {
+ bFaceMap *next_fmap = fmap->next;
+ fmap_remove_exec(ob, fmap, edit_mode, false);
+ fmap = next_fmap;
+ }
+ }
+ /* remove all face-maps */
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+ CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0);
+ }
+ ob->actfmap = 0;
+}
+
+int BKE_object_facemap_name_index(Object *ob, const char *name)
+{
+ return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1;
+}
+
+bFaceMap *BKE_object_facemap_find_name(Object *ob, const char *name)
+{
+ return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
+}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index bb738033f02..902237d7ac8 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -28,22 +28,22 @@
*/
#include "DNA_anim_types.h"
+#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
-#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
-#include "BLI_threads.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_constraint.h"
-#include "BKE_depsgraph.h"
+#include "BKE_curve.h"
#include "BKE_DerivedMesh.h"
#include "BKE_displist.h"
#include "BKE_editmesh.h"
@@ -53,21 +53,26 @@
#include "BKE_key.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
+#include "BKE_gpencil.h"
+
+#include "MEM_guardedalloc.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
-static ThreadMutex material_lock = BLI_MUTEX_INITIALIZER;
-void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
- Object *ob)
+void BKE_object_eval_local_transform(Depsgraph *depsgraph, Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* calculate local matrix */
BKE_object_to_mat4(ob, ob->obmat);
@@ -75,7 +80,7 @@ void BKE_object_eval_local_transform(EvaluationContext *UNUSED(eval_ctx),
/* Evaluate parent */
/* NOTE: based on solve_parenting(), but with the cruft stripped out */
-void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
+void BKE_object_eval_parent(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
@@ -85,14 +90,14 @@ void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
float tmat[4][4];
float locmat[4][4];
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* get local matrix (but don't calculate it, as that was done already!) */
// XXX: redundant?
copy_m4_m4(locmat, ob->obmat);
/* get parent effect matrix */
- BKE_object_get_parent_matrix(scene, ob, par, totmat);
+ BKE_object_get_parent_matrix(depsgraph, scene, ob, par, totmat);
/* total */
mul_m4_m4m4(tmat, totmat, ob->parentinv);
@@ -107,14 +112,14 @@ void BKE_object_eval_parent(EvaluationContext *UNUSED(eval_ctx),
}
}
-void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
+void BKE_object_eval_constraints(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
bConstraintOb *cob;
float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* evaluate constraints stack */
/* TODO: split this into:
@@ -125,23 +130,38 @@ void BKE_object_eval_constraints(EvaluationContext *UNUSED(eval_ctx),
* Not sure why, this is from Joshua - sergey
*
*/
- cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
- BKE_constraints_solve(&ob->constraints, cob, ctime);
+ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime);
BKE_constraints_clear_evalob(cob);
}
-void BKE_object_eval_done(EvaluationContext *UNUSED(eval_ctx), Object *ob)
+void BKE_object_eval_done(Depsgraph *depsgraph, Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* Set negative scale flag in object. */
if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE;
else ob->transflag &= ~OB_NEG_SCALE;
+
+ if (DEG_is_active(depsgraph)) {
+ Object *ob_orig = DEG_get_original_object(ob);
+ copy_m4_m4(ob_orig->obmat, ob->obmat);
+ copy_m4_m4(ob_orig->constinv, ob->constinv);
+ ob_orig->transflag = ob->transflag;
+ ob_orig->flag = ob->flag;
+
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (bb != NULL) {
+ if (ob_orig->bb == NULL) {
+ ob_orig->bb = MEM_mallocN(sizeof(*ob_orig->bb), __func__);
+ }
+ *ob_orig->bb = *bb;
+ }
+ }
}
void BKE_object_handle_data_update(
- Main *bmain,
- EvaluationContext *eval_ctx,
+ Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
@@ -150,40 +170,47 @@ void BKE_object_handle_data_update(
Key *key;
float ctime = BKE_scene_frame_get(scene);
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL)
- printf("recalcdata %s\n", ob->id.name + 2);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
/* TODO(sergey): Only used by legacy depsgraph. */
if (adt) {
/* evaluate drivers - datalevel */
- /* XXX: for mesh types, should we push this to derivedmesh instead? */
- BKE_animsys_evaluate_animdata(scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
+ /* XXX: for mesh types, should we push this to evaluated mesh instead? */
+ BKE_animsys_evaluate_animdata(depsgraph, scene, data_id, adt, ctime, ADT_RECALC_DRIVERS);
}
/* TODO(sergey): Only used by legacy depsgraph. */
key = BKE_key_from_object(ob);
if (key && key->block.first) {
if (!(ob->shapeflag & OB_SHAPE_LOCK))
- BKE_animsys_evaluate_animdata(scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &key->id, key->adt, ctime, ADT_RECALC_DRIVERS);
}
/* includes all keys and modifiers */
switch (ob->type) {
case OB_MESH:
{
- BMEditMesh *em = (ob == scene->obedit) ? BKE_editmesh_from_object(ob) : NULL;
+#if 0
+ BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? BKE_editmesh_from_object(ob) : NULL;
+#else
+ BMEditMesh *em = (ob->mode & OB_MODE_EDIT) ? ((Mesh *)ob->data)->edit_btmesh : NULL;
+ if (em && em->ob != ob) {
+ em = NULL;
+ }
+#endif
+
uint64_t data_mask = scene->customdata_mask | CD_MASK_BAREMESH;
#ifdef WITH_FREESTYLE
/* make sure Freestyle edge/face marks appear in DM for render (see T40315) */
- if (eval_ctx->mode != DAG_EVAL_VIEWPORT) {
+ if (DEG_get_mode(depsgraph) != DAG_EVAL_VIEWPORT) {
data_mask |= CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
}
#endif
if (em) {
- makeDerivedMesh(scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */
+ makeDerivedMesh(depsgraph, scene, ob, em, data_mask, false); /* was CD_MASK_BAREMESH */
}
else {
- makeDerivedMesh(scene, ob, NULL, data_mask, false);
+ makeDerivedMesh(depsgraph, scene, ob, NULL, data_mask, false);
}
break;
}
@@ -195,75 +222,48 @@ void BKE_object_handle_data_update(
}
}
else {
- BKE_pose_where_is(scene, ob);
+ BKE_pose_where_is(depsgraph, scene, ob);
}
break;
case OB_MBALL:
- BKE_displist_make_mball(bmain, eval_ctx, scene, ob);
+ BKE_displist_make_mball(depsgraph, scene, ob);
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
- BKE_displist_make_curveTypes(scene, ob, 0);
+ BKE_displist_make_curveTypes(depsgraph, scene, ob, 0);
break;
case OB_LATTICE:
- BKE_lattice_modifiers_calc(scene, ob);
+ BKE_lattice_modifiers_calc(depsgraph, scene, ob);
break;
case OB_EMPTY:
if (ob->empty_drawtype == OB_EMPTY_IMAGE && ob->data)
if (BKE_image_is_animated(ob->data))
- BKE_image_user_check_frame_calc(ob->iuser, (int)ctime, 0);
+ BKE_image_user_check_frame_calc(ob->iuser, (int)ctime);
break;
}
- /* related materials */
- /* XXX: without depsgraph tagging, this will always need to be run, which will be slow!
- * However, not doing anything (or trying to hack around this lack) is not an option
- * anymore, especially due to Cycles [#31834]
- */
- if (ob->totcol) {
- int a;
- if (ob->totcol != 0) {
- BLI_mutex_lock(&material_lock);
- for (a = 1; a <= ob->totcol; a++) {
- Material *ma = give_current_material(ob, a);
- if (ma) {
- /* recursively update drivers for this material */
- material_drivers_update(scene, ma, ctime);
- }
- }
- BLI_mutex_unlock(&material_lock);
- }
- }
- else if (ob->type == OB_LAMP)
- lamp_drivers_update(scene, ob->data, ctime);
-
/* particles */
- if (ob != scene->obedit && ob->particlesystem.first) {
+ if (!(ob->mode & OB_MODE_EDIT) && ob->particlesystem.first) {
+ const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
ParticleSystem *tpsys, *psys;
- DerivedMesh *dm;
ob->transflag &= ~OB_DUPLIPARTS;
psys = ob->particlesystem.first;
while (psys) {
- /* ensure this update always happens even if psys is disabled */
- if (psys->recalc & PSYS_RECALC_TYPE) {
- psys_changed_type(ob, psys);
- }
-
- if (psys_check_enabled(ob, psys, eval_ctx->mode == DAG_EVAL_RENDER)) {
+ if (psys_check_enabled(ob, psys, use_render_params)) {
/* check use of dupli objects here */
- if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) &&
+ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || use_render_params) &&
((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) ||
(psys->part->ren_as == PART_DRAW_GR && psys->part->dup_group)))
{
ob->transflag |= OB_DUPLIPARTS;
}
- particle_system_update(bmain, scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER));
+ particle_system_update(depsgraph, scene, ob, psys, use_render_params);
psys = psys->next;
}
else if (psys->flag & PSYS_DELETE) {
@@ -275,28 +275,17 @@ void BKE_object_handle_data_update(
else
psys = psys->next;
}
-
- if (eval_ctx->mode == DAG_EVAL_RENDER && ob->transflag & OB_DUPLIPARTS) {
- /* this is to make sure we get render level duplis in groups:
- * the derivedmesh must be created before init_render_mesh,
- * since object_duplilist does dupliparticles before that */
- CustomDataMask data_mask = CD_MASK_BAREMESH | CD_MASK_MFACE | CD_MASK_MTFACE | CD_MASK_MCOL;
- dm = mesh_create_derived_render(scene, ob, data_mask);
- dm->release(dm);
-
- for (psys = ob->particlesystem.first; psys; psys = psys->next)
- psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
- }
}
/* quick cache removed */
}
-bool BKE_object_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx),
+bool BKE_object_eval_proxy_copy(Depsgraph *depsgraph,
Object *object)
{
/* Handle proxy copy for target, */
if (ID_IS_LINKED(object) && object->proxy_from) {
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
if (object->proxy_from->proxy_group) {
/* Transform proxy into group space. */
Object *obg = object->proxy_from->proxy_group;
@@ -316,46 +305,136 @@ bool BKE_object_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx),
return false;
}
-void BKE_object_eval_uber_transform(EvaluationContext *eval_ctx, Object *object)
+void BKE_object_eval_uber_transform(Depsgraph *depsgraph, Object *object)
+{
+ BKE_object_eval_proxy_copy(depsgraph, object);
+}
+
+void BKE_object_batch_cache_dirty_tag(Object *ob)
{
- BKE_object_eval_proxy_copy(eval_ctx, object);
- object->recalc &= ~(OB_RECALC_OB | OB_RECALC_TIME);
- if (object->data == NULL) {
- object->recalc &= ~OB_RECALC_DATA;
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+ break;
+ case OB_LATTICE:
+ BKE_lattice_batch_cache_dirty_tag(ob->data, BKE_LATTICE_BATCH_DIRTY_ALL);
+ break;
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ BKE_curve_batch_cache_dirty_tag(ob->data, BKE_CURVE_BATCH_DIRTY_ALL);
+ break;
+ case OB_MBALL:
+ BKE_mball_batch_cache_dirty_tag(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
+ break;
+ case OB_GPENCIL:
+ BKE_gpencil_batch_cache_dirty_tag(ob->data);
+ break;
}
}
-void BKE_object_eval_uber_data(Main *bmain, EvaluationContext *eval_ctx,
+void BKE_object_eval_uber_data(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
BLI_assert(ob->type != OB_ARMATURE);
- BKE_object_handle_data_update(bmain, eval_ctx, scene, ob);
-
- ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
+ BKE_object_handle_data_update(depsgraph, scene, ob);
+ BKE_object_batch_cache_dirty_tag(ob);
}
-void BKE_object_eval_cloth(EvaluationContext *UNUSED(eval_ctx),
+void BKE_object_eval_cloth(Depsgraph *depsgraph,
Scene *scene,
Object *object)
{
- DEG_debug_print_eval(__func__, object->id.name, object);
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH);
}
-void BKE_object_eval_transform_all(EvaluationContext *eval_ctx,
+void BKE_object_eval_transform_all(Depsgraph *depsgraph,
Scene *scene,
Object *object)
{
/* This mimics full transform update chain from new depsgraph. */
- BKE_object_eval_local_transform(eval_ctx, object);
+ BKE_object_eval_local_transform(depsgraph, object);
if (object->parent != NULL) {
- BKE_object_eval_parent(eval_ctx, scene, object);
+ BKE_object_eval_parent(depsgraph, scene, object);
}
if (!BLI_listbase_is_empty(&object->constraints)) {
- BKE_object_eval_constraints(eval_ctx, scene, object);
+ BKE_object_eval_constraints(depsgraph, scene, object);
+ }
+ BKE_object_eval_uber_transform(depsgraph, object);
+ BKE_object_eval_done(depsgraph, object);
+}
+
+void BKE_object_eval_update_shading(Depsgraph *depsgraph, Object *object)
+{
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+ if (object->type == OB_MESH) {
+ BKE_mesh_batch_cache_dirty_tag(object->data, BKE_MESH_BATCH_DIRTY_SHADING);
+ }
+}
+
+void BKE_object_data_select_update(Depsgraph *depsgraph, ID *object_data)
+{
+ DEG_debug_print_eval(depsgraph, __func__, object_data->name, object_data);
+ switch (GS(object_data->name)) {
+ case ID_ME:
+ BKE_mesh_batch_cache_dirty_tag(
+ (Mesh *)object_data,
+ BKE_MESH_BATCH_DIRTY_SELECT);
+ break;
+ case ID_CU:
+ BKE_curve_batch_cache_dirty_tag(
+ (Curve *)object_data,
+ BKE_CURVE_BATCH_DIRTY_SELECT);
+ break;
+ case ID_LT:
+ BKE_lattice_batch_cache_dirty_tag(
+ (struct Lattice *)object_data,
+ BKE_LATTICE_BATCH_DIRTY_SELECT);
+ break;
+ default:
+ break;
+ }
+}
+
+void BKE_object_eval_flush_base_flags(Depsgraph *depsgraph,
+ Scene *scene, const int view_layer_index,
+ Object *object, int base_index,
+ const bool is_from_set)
+{
+ /* TODO(sergey): Avoid list lookup. */
+ BLI_assert(view_layer_index >= 0);
+ ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index);
+ BLI_assert(view_layer != NULL);
+ BLI_assert(view_layer->object_bases_array != NULL);
+ BLI_assert(base_index >= 0);
+ BLI_assert(base_index < MEM_allocN_len(view_layer->object_bases_array) / sizeof(Base *));
+ Base *base = view_layer->object_bases_array[base_index];
+ BLI_assert(base->object == object);
+
+ DEG_debug_print_eval(depsgraph, __func__, object->id.name, object);
+
+ /* Copy flags and settings from base. */
+ object->base_flag = base->flag;
+ if (is_from_set) {
+ object->base_flag |= BASE_FROM_SET;
+ object->base_flag &= ~(BASE_SELECTED | BASE_SELECTABLE);
+ }
+
+ /* Copy to original object datablock if needed. */
+ if (DEG_is_active(depsgraph)) {
+ Object *object_orig = DEG_get_original_object(object);
+ object_orig->base_flag = object->base_flag;
+ }
+
+ if (object->mode == OB_MODE_PARTICLE_EDIT) {
+ for (ParticleSystem *psys = object->particlesystem.first;
+ psys != NULL;
+ psys = psys->next)
+ {
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ }
}
- BKE_object_eval_uber_transform(eval_ctx, object);
- BKE_object_eval_done(eval_ctx, object);
}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 7f3f916964a..adbe1a7f889 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "BLI_math.h"
@@ -241,14 +242,6 @@ static void init_complex(fftw_complex cmpl, float real, float image)
cmpl[1] = image;
}
-#if 0 /* unused */
-static void add_complex_f(fftw_complex res, fftw_complex cmpl, float f)
-{
- res[0] = cmpl[0] + f;
- res[1] = cmpl[1];
-}
-#endif
-
static void add_comlex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2)
{
res[0] = cmpl1[0] + cmpl2[0];
@@ -774,15 +767,6 @@ void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount
if (o->_do_normals) {
BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, TASK_PRIORITY_HIGH);
BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, TASK_PRIORITY_HIGH);
-
-#if 0
- for (i = 0; i < o->_M; ++i) {
- for (j = 0; j < o->_N; ++j) {
- o->_N_y[i * o->_N + j] = 1.0f / scale;
- }
- }
- (MEM01)
-#endif
o->_N_y = 1.0f / scale;
}
@@ -835,6 +819,35 @@ struct Ocean *BKE_ocean_add(void)
return oc;
}
+bool BKE_ocean_ensure(struct OceanModifierData *omd)
+{
+ if (omd->ocean) {
+ return false;
+ }
+
+ omd->ocean = BKE_ocean_add();
+ BKE_ocean_init_from_modifier(omd->ocean, omd);
+ return true;
+}
+
+void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData const *omd)
+{
+ short do_heightfield, do_chop, do_normals, do_jacobian;
+
+ do_heightfield = true;
+ do_chop = (omd->chop_amount > 0);
+ do_normals = (omd->flag & MOD_OCEAN_GENERATE_NORMALS);
+ do_jacobian = (omd->flag & MOD_OCEAN_GENERATE_FOAM);
+
+ BKE_ocean_free_data(ocean);
+ BKE_ocean_init(ocean, omd->resolution * omd->resolution, omd->resolution * omd->resolution,
+ omd->spatial_size, omd->spatial_size,
+ omd->wind_velocity, omd->smallest_wave, 1.0, omd->wave_direction, omd->damp, omd->wave_alignment,
+ omd->depth, omd->time,
+ do_heightfield, do_chop, do_normals, do_jacobian,
+ omd->seed);
+}
+
void BKE_ocean_init(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp,
float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals,
short do_jacobian, int seed)
@@ -1227,30 +1240,12 @@ void BKE_ocean_simulate_cache(struct OceanCache *och, int frame)
cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_DISPLACE);
och->ibufs_disp[f] = IMB_loadiffname(string, 0, NULL);
-#if 0
- if (och->ibufs_disp[f] == NULL)
- printf("error loading %s\n", string);
- else
- printf("loaded cache %s\n", string);
-#endif
cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_FOAM);
och->ibufs_foam[f] = IMB_loadiffname(string, 0, NULL);
-#if 0
- if (och->ibufs_foam[f] == NULL)
- printf("error loading %s\n", string);
- else
- printf("loaded cache %s\n", string);
-#endif
cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_NORMAL);
och->ibufs_norm[f] = IMB_loadiffname(string, 0, NULL);
-#if 0
- if (och->ibufs_norm[f] == NULL)
- printf("error loading %s\n", string);
- else
- printf("loaded cache %s\n", string);
-#endif
}
@@ -1325,13 +1320,6 @@ void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v
* break up the foam where height (Y) is low (wave valley), and X and Z displacement is greatest
*/
-#if 0
- vec[0] = ocr.disp[0];
- vec[1] = ocr.disp[2];
- hor_stretch = len_v2(vec);
- CLAMP(hor_stretch, 0.0, 1.0);
-#endif
-
neg_disp = ocr.disp[1] < 0.0f ? 1.0f + ocr.disp[1] : 1.0f;
neg_disp = neg_disp < 0.0f ? 0.0f : neg_disp;
@@ -1339,15 +1327,6 @@ void BKE_ocean_bake(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v
neg_eplus = ocr.Eplus[2] < 0.0f ? 1.0f + ocr.Eplus[2] : 1.0f;
neg_eplus = neg_eplus < 0.0f ? 0.0f : neg_eplus;
-#if 0
- if (ocr.disp[1] < 0.0 || r > och->foam_fade)
- pr *= och->foam_fade;
-
-
- pr = pr * (1.0 - hor_stretch) * ocr.disp[1];
- pr = pr * neg_disp * neg_eplus;
-#endif
-
if (pr < 1.0f)
pr *= pr;
@@ -1511,4 +1490,16 @@ void BKE_ocean_bake(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och),
/* unused */
(void)update_cb;
}
+
+void BKE_ocean_init_from_modifier(struct Ocean *UNUSED(ocean), struct OceanModifierData const *UNUSED(omd))
+{
+}
+
#endif /* WITH_OCEANSIM */
+
+void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd)
+{
+ BKE_ocean_free_cache(omd->oceancache);
+ omd->oceancache = NULL;
+ omd->cached = false;
+}
diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c
index 9db9b2ddf54..fb62645ef43 100644
--- a/source/blender/blenkernel/intern/outliner_treehash.c
+++ b/source/blender/blenkernel/intern/outliner_treehash.c
@@ -27,6 +27,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -40,6 +41,7 @@
typedef struct TseGroup {
TreeStoreElem **elems;
+ int lastused;
int size;
int allocated;
} TseGroup;
@@ -53,10 +55,11 @@ static TseGroup *tse_group_create(void)
tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems");
tse_group->size = 0;
tse_group->allocated = 1;
+ tse_group->lastused = 0;
return tse_group;
}
-static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
+static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem)
{
if (UNLIKELY(tse_group->size == tse_group->allocated)) {
tse_group->allocated *= 2;
@@ -66,6 +69,26 @@ static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
tse_group->size++;
}
+static void tse_group_remove_element(TseGroup *tse_group, TreeStoreElem *elem)
+{
+ int min_allocated = MAX2(1, tse_group->allocated / 2);
+ BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0);
+
+ tse_group->size--;
+ BLI_assert(tse_group->size >= 0);
+ for (int i = 0; i < tse_group->size; i++) {
+ if (tse_group->elems[i] == elem) {
+ memcpy(tse_group->elems[i], tse_group->elems[i + 1], (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *));
+ break;
+ }
+ }
+
+ if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) {
+ tse_group->allocated = min_allocated;
+ tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated);
+ }
+}
+
static void tse_group_free(TseGroup *tse_group)
{
MEM_freeN(tse_group->elems);
@@ -122,6 +145,16 @@ static void free_treehash_group(void *key)
tse_group_free(key);
}
+void BKE_outliner_treehash_clear_used(void *treehash)
+{
+ GHashIterator gh_iter;
+
+ GHASH_ITER(gh_iter, treehash) {
+ TseGroup *group = BLI_ghashIterator_getValue(&gh_iter);
+ group->lastused = 0;
+ }
+}
+
void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore)
{
BLI_assert(treehash);
@@ -140,7 +173,22 @@ void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem)
*val_p = tse_group_create();
}
group = *val_p;
- tse_group_add(group, elem);
+ group->lastused = 0;
+ tse_group_add_element(group, elem);
+}
+
+void BKE_outliner_treehash_remove_element(void *treehash, TreeStoreElem *elem)
+{
+ TseGroup *group = BLI_ghash_lookup(treehash, elem);
+
+ BLI_assert(group != NULL);
+ if (group->size <= 1) {
+ /* one element -> remove group completely */
+ BLI_ghash_remove(treehash, elem, NULL, free_treehash_group);
+ }
+ else {
+ tse_group_remove_element(group, elem);
+ }
}
static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id)
@@ -163,10 +211,19 @@ TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, short type, s
group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id);
if (group) {
- int i;
- for (i = 0; i < group->size; i++) {
- if (!group->elems[i]->used) {
- return group->elems[i];
+ /* Find unused element, with optimization to start from previously
+ * found element assuming we do repeated lookups. */
+ int size = group->size;
+ int offset = group->lastused;
+
+ for (int i = 0; i < size; i++, offset++) {
+ if (offset >= size) {
+ offset = 0;
+ }
+
+ if (!group->elems[offset]->used) {
+ group->lastused = offset;
+ return group->elems[offset];
}
}
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 0637fc4f00c..0446b697c68 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -54,6 +54,7 @@
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
@@ -264,33 +265,6 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
BKE_report(reports, RPT_INFO, "No new files have been packed");
}
-
-#if 0
-
-// attempt to create a function that generates an unique filename
-// this will work when all functions in fileops.c understand relative filenames...
-
-static char *find_new_name(char *name)
-{
- char tempname[FILE_MAX];
- char *newname;
- size_t len;
-
- if (fop_exists(name)) {
- for (number = 1; number <= 999; number++) {
- BLI_snprintf(tempname, sizeof(tempname), "%s.%03d", name, number);
- if (!fop_exists(tempname)) {
- break;
- }
- }
- }
- len = strlen(tempname) + 1;
- newname = MEM_mallocN(len, "find_new_name");
- memcpy(newname, tempname, len * sizeof(char));
- return newname;
-}
-#endif
-
int writePackedFile(
ReportList *reports, const char *ref_file_name, const char *filename, PackedFile *pf, const bool guimode)
{
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 0541bd58c85..e31021d7d48 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -41,30 +41,46 @@
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "DNA_space_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_bitmap.h"
+#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_string_utils.h"
#include "BLI_math_vector.h"
#include "BLI_listbase.h"
+#include "BLT_translation.h"
+
+#include "BKE_animsys.h"
#include "BKE_brush.h"
+#include "BKE_ccg.h"
#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_main.h"
#include "BKE_context.h"
#include "BKE_crazyspace.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "RNA_enum_types.h"
+
#include "bmesh.h"
const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100};
@@ -74,9 +90,9 @@ const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255};
static eOverlayControlFlags overlay_flags = 0;
-void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
+void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, view_layer);
Brush *br = p->brush;
if (!br)
@@ -88,9 +104,9 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, const Tex *tex)
overlay_flags |= PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY;
}
-void BKE_paint_invalidate_cursor_overlay(Scene *scene, CurveMapping *curve)
+void BKE_paint_invalidate_cursor_overlay(Scene *scene, ViewLayer *view_layer, CurveMapping *curve)
{
- Paint *p = BKE_paint_get_active(scene);
+ Paint *p = BKE_paint_get_active(scene, view_layer);
Brush *br = p->brush;
if (br && br->curve == curve)
@@ -146,6 +162,8 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
return &ts->imapaint.paint;
case ePaintSculptUV:
return &ts->uvsculpt->paint;
+ case ePaintGpencil:
+ return &ts->gp_paint->paint;
case ePaintInvalid:
return NULL;
default:
@@ -156,13 +174,50 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
return NULL;
}
-Paint *BKE_paint_get_active(Scene *sce)
+const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode)
{
- if (sce) {
+ switch (mode) {
+ case ePaintSculpt:
+ return rna_enum_brush_sculpt_tool_items;
+ case ePaintVertex:
+ return rna_enum_brush_vertex_tool_items;
+ case ePaintWeight:
+ return rna_enum_brush_weight_tool_items;
+ case ePaintTexture2D:
+ case ePaintTexture3D:
+ return rna_enum_brush_image_tool_items;
+ case ePaintSculptUV:
+ return NULL;
+ case ePaintGpencil:
+ return rna_enum_brush_gpencil_types_items;
+ case ePaintInvalid:
+ break;
+ }
+ return NULL;
+}
+
+const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode)
+{
+ switch (mode) {
+ case ePaintSculpt: return "sculpt_tool";
+ case ePaintVertex: return "vertex_tool";
+ case ePaintWeight: return "weight_tool";
+ case ePaintTexture2D:
+ case ePaintTexture3D: return "image_tool";
+ case ePaintGpencil: return "gpencil_tool";
+ default:
+ /* invalid paint mode */
+ return NULL;
+ }
+}
+
+Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
+{
+ if (sce && view_layer) {
ToolSettings *ts = sce->toolsettings;
- if (sce->basact && sce->basact->object) {
- switch (sce->basact->object->mode) {
+ if (view_layer->basact && view_layer->basact->object) {
+ switch (view_layer->basact->object->mode) {
case OB_MODE_SCULPT:
return &ts->sculpt->paint;
case OB_MODE_VERTEX_PAINT:
@@ -171,10 +226,14 @@ Paint *BKE_paint_get_active(Scene *sce)
return &ts->wpaint->paint;
case OB_MODE_TEXTURE_PAINT:
return &ts->imapaint.paint;
+ case OB_MODE_GPENCIL_PAINT:
+ return &ts->gp_paint->paint;
case OB_MODE_EDIT:
if (ts->use_uv_sculpt)
return &ts->uvsculpt->paint;
return &ts->imapaint.paint;
+ default:
+ break;
}
}
@@ -188,14 +247,15 @@ Paint *BKE_paint_get_active(Scene *sce)
Paint *BKE_paint_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && view_layer) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (view_layer->basact && view_layer->basact->object)
+ obact = view_layer->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
@@ -209,7 +269,7 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
}
}
else {
- return BKE_paint_get_active(sce);
+ return BKE_paint_get_active(sce, view_layer);
}
}
@@ -219,14 +279,15 @@ Paint *BKE_paint_get_active_from_context(const bContext *C)
ePaintMode BKE_paintmode_get_active_from_context(const bContext *C)
{
Scene *sce = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima;
- if (sce) {
+ if (sce && view_layer) {
ToolSettings *ts = sce->toolsettings;
Object *obact = NULL;
- if (sce->basact && sce->basact->object)
- obact = sce->basact->object;
+ if (view_layer->basact && view_layer->basact->object)
+ obact = view_layer->basact->object;
if ((sima = CTX_wm_space_image(C)) != NULL) {
if (obact && obact->mode == OB_MODE_EDIT) {
@@ -266,6 +327,32 @@ ePaintMode BKE_paintmode_get_active_from_context(const bContext *C)
return ePaintInvalid;
}
+ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref)
+{
+ if (tref->space_type == SPACE_VIEW3D) {
+ switch (tref->mode) {
+ case CTX_MODE_SCULPT:
+ return ePaintSculpt;
+ case CTX_MODE_PAINT_VERTEX:
+ return ePaintVertex;
+ case CTX_MODE_PAINT_WEIGHT:
+ return ePaintWeight;
+ case CTX_MODE_GPENCIL_PAINT:
+ return ePaintGpencil;
+ case CTX_MODE_PAINT_TEXTURE:
+ return ePaintTexture3D;
+ }
+ }
+ else if (tref->space_type == SPACE_IMAGE) {
+ switch (tref->mode) {
+ case SI_MODE_PAINT:
+ return ePaintTexture2D;
+ }
+ }
+
+ return ePaintInvalid;
+}
+
Brush *BKE_paint_brush(Paint *p)
{
return p ? p->brush : NULL;
@@ -277,9 +364,64 @@ void BKE_paint_brush_set(Paint *p, Brush *br)
id_us_min((ID *)p->brush);
id_us_plus((ID *)br);
p->brush = br;
+
+ BKE_paint_toolslots_brush_update(p);
+ }
+}
+
+void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint)
+{
+ if (paint == &ts->imapaint.paint) {
+ paint->runtime.tool_offset = offsetof(Brush, imagepaint_tool);
+ paint->runtime.ob_mode = OB_MODE_TEXTURE_PAINT;
+ }
+ else if (paint == &ts->sculpt->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, sculpt_tool);
+ paint->runtime.ob_mode = OB_MODE_SCULPT;
+ }
+ else if (paint == &ts->vpaint->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, vertexpaint_tool);
+ paint->runtime.ob_mode = OB_MODE_VERTEX_PAINT;
+ }
+ else if (paint == &ts->wpaint->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, weightpaint_tool);
+ paint->runtime.ob_mode = OB_MODE_WEIGHT_PAINT;
+ }
+ else if (paint == &ts->gp_paint->paint) {
+ paint->runtime.tool_offset = offsetof(Brush, gpencil_tool);
+ paint->runtime.ob_mode = OB_MODE_GPENCIL_PAINT;
+ }
+ else if (paint == &ts->uvsculpt->paint) {
+ /* We don't use these yet. */
+ paint->runtime.tool_offset = 0;
+ paint->runtime.ob_mode = 0;
+ }
+ else {
+ BLI_assert(0);
}
}
+uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode)
+{
+ switch (mode) {
+ case ePaintTexture2D:
+ case ePaintTexture3D:
+ return offsetof(Brush, imagepaint_tool);
+ case ePaintSculpt:
+ return offsetof(Brush, sculpt_tool);
+ case ePaintVertex:
+ return offsetof(Brush, vertexpaint_tool);
+ case ePaintWeight:
+ return offsetof(Brush, weightpaint_tool);
+ case ePaintGpencil:
+ return offsetof(Brush, gpencil_tool);
+ case ePaintSculptUV:
+ case ePaintInvalid:
+ break; /* We don't use these yet. */
+ }
+ return 0;
+}
+
/** Free (or release) any data used by this paint curve (does not free the pcurve itself). */
void BKE_paint_curve_free(PaintCurve *pc)
{
@@ -332,8 +474,8 @@ void BKE_paint_palette_set(Paint *p, Palette *palette)
{
if (p) {
id_us_min((ID *)p->palette);
- id_us_plus((ID *)palette);
p->palette = palette;
+ id_us_plus((ID *)p->palette);
}
}
@@ -341,8 +483,8 @@ void BKE_paint_curve_set(Brush *br, PaintCurve *pc)
{
if (br) {
id_us_min((ID *)br->paint_curve);
- id_us_plus((ID *)pc);
br->paint_curve = pc;
+ id_us_plus((ID *)br->paint_curve);
}
}
@@ -375,13 +517,7 @@ void BKE_palette_clear(Palette *palette)
Palette *BKE_palette_add(Main *bmain, const char *name)
{
- Palette *palette;
-
- palette = BKE_libblock_alloc(bmain, ID_PAL, name, 0);
-
- /* enable fake user by default */
- id_fake_user_set(&palette->id);
-
+ Palette *palette = BKE_id_new(bmain, ID_PAL, name);
return palette;
}
@@ -410,6 +546,12 @@ void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local)
BKE_id_make_local_generic(bmain, &palette->id, true, lib_local);
}
+void BKE_palette_init(Palette *palette)
+{
+ /* Enable fake user by default. */
+ id_fake_user_set(&palette->id);
+}
+
/** Free (or release) any data used by this palette (does not free the palette itself). */
void BKE_palette_free(Palette *palette)
{
@@ -418,19 +560,17 @@ void BKE_palette_free(Palette *palette)
PaletteColor *BKE_palette_color_add(Palette *palette)
{
- PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color");
+ PaletteColor *color = MEM_callocN(sizeof(*color), "Palette Color");
BLI_addtail(&palette->colors, color);
return color;
}
-
bool BKE_palette_is_empty(const struct Palette *palette)
{
return BLI_listbase_is_empty(&palette->colors);
}
-
-/* are we in vertex paint or weight pain face select mode? */
+/* are we in vertex paint or weight paint face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
return ( (ob != NULL) &&
@@ -477,7 +617,7 @@ void BKE_paint_cavity_curve_preset(Paint *p, int preset)
curvemapping_changed(p->cavity_curve, false);
}
-eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode)
+eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode)
{
switch (mode) {
case ePaintSculpt:
@@ -486,9 +626,8 @@ eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode)
return OB_MODE_VERTEX_PAINT;
case ePaintWeight:
return OB_MODE_WEIGHT_PAINT;
- case ePaintTexture3D:
- return OB_MODE_TEXTURE_PAINT;
case ePaintTexture2D:
+ case ePaintTexture3D:
return OB_MODE_TEXTURE_PAINT;
case ePaintSculptUV:
return OB_MODE_EDIT;
@@ -498,6 +637,64 @@ eObjectMode BKE_paint_object_mode_from_paint_mode(ePaintMode mode)
}
}
+/**
+ * Call when entering each respective paint mode.
+ */
+bool BKE_paint_ensure(const ToolSettings *ts, struct Paint **r_paint)
+{
+ Paint *paint = NULL;
+ if (*r_paint) {
+ /* Note: 'ts->imapaint' is ignored, it's not allocated. */
+ BLI_assert(
+ ELEM(*r_paint,
+ &ts->gp_paint->paint,
+ &ts->sculpt->paint,
+ &ts->vpaint->paint,
+ &ts->wpaint->paint,
+ &ts->uvsculpt->paint));
+
+#ifdef DEBUG
+ struct Paint paint_test = **r_paint;
+ BKE_paint_runtime_init(ts, *r_paint);
+ /* Swap so debug doesn't hide errors when release fails. */
+ SWAP(Paint, **r_paint, paint_test);
+ BLI_assert(paint_test.runtime.ob_mode == (*r_paint)->runtime.ob_mode);
+ BLI_assert(paint_test.runtime.tool_offset == (*r_paint)->runtime.tool_offset);
+#endif
+ return true;
+ }
+
+ if (ELEM(*r_paint, &ts->vpaint->paint, &ts->wpaint->paint)) {
+ VPaint *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+ }
+ else if (*r_paint == &ts->sculpt->paint) {
+ Sculpt *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+
+ /* Turn on X plane mirror symmetry by default */
+ paint->symmetry_flags |= PAINT_SYMM_X;
+
+ /* Make sure at least dyntopo subdivision is enabled */
+ data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
+ }
+ else if (*r_paint == &ts->gp_paint->paint) {
+ GpPaint *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+ }
+ else if (*r_paint == &ts->uvsculpt->paint) {
+ UvSculpt *data = MEM_callocN(sizeof(*data), __func__);
+ paint = &data->paint;
+ }
+
+ paint->flags |= PAINT_SHOW_BRUSH;
+
+ BKE_paint_runtime_init(ts, paint);
+
+ *r_paint = paint;
+ return false;
+}
+
void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3])
{
UnifiedPaintSettings *ups = &sce->toolsettings->unified_paint_settings;
@@ -507,7 +704,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3])
/* If there's no brush, create one */
brush = BKE_paint_brush(paint);
if (brush == NULL) {
- eObjectMode ob_mode = BKE_paint_object_mode_from_paint_mode(mode);
+ eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode);
brush = BKE_brush_first_search(bmain, ob_mode);
if (!brush) {
@@ -529,6 +726,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3])
void BKE_paint_free(Paint *paint)
{
curvemapping_free(paint->cavity_curve);
+ MEM_SAFE_FREE(paint->tool_slots);
}
/* called when copying scene settings, so even if 'src' and 'tar' are the same
@@ -539,10 +737,16 @@ void BKE_paint_copy(Paint *src, Paint *tar, const int flag)
{
tar->brush = src->brush;
tar->cavity_curve = curvemapping_copy(src->cavity_curve);
+ tar->tool_slots = MEM_dupallocN(src->tool_slots);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus((ID *)tar->brush);
id_us_plus((ID *)tar->palette);
+ if (src->tool_slots != NULL) {
+ for (int i = 0; i < tar->tool_slots_len; i++) {
+ id_us_plus((ID *)tar->tool_slots[i].brush);
+ }
+ }
}
}
@@ -713,8 +917,8 @@ void BKE_sculptsession_bm_to_me(Object *ob, bool reorder)
if (ob && ob->sculpt) {
sculptsession_bm_to_me_update_data_only(ob, reorder);
- /* ensure the objects DerivedMesh mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ /* ensure the objects evaluated mesh doesn't hold onto arrays now realloc'd in the mesh [#34473] */
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
@@ -724,7 +928,7 @@ void BKE_sculptsession_bm_to_me_for_render(Object *object)
if (object->sculpt->bm) {
/* Ensure no points to old arrays are stored in DM
*
- * Apparently, we could not use DAG_id_tag_update
+ * Apparently, we could not use DEG_id_tag_update
* here because this will lead to the while object
* surface to disappear, so we'll release DM in place.
*/
@@ -749,7 +953,6 @@ void BKE_sculptsession_free(Object *ob)
{
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
- DerivedMesh *dm = ob->derivedFinal;
if (ss->bm) {
BKE_sculptsession_bm_to_me(ob, true);
@@ -758,12 +961,11 @@ void BKE_sculptsession_free(Object *ob)
if (ss->pbvh)
BKE_pbvh_free(ss->pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
if (ss->bm_log)
BM_log_free(ss->bm_log);
- if (dm && dm->getPBVH)
- dm->getPBVH(NULL, dm); /* signal to clear */
-
if (ss->texcache)
MEM_freeN(ss->texcache);
@@ -853,14 +1055,25 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
}
/**
- * \param need_mask So the DerivedMesh thats returned has mask data
+ * \param need_mask So that the evaluated mesh that is returned has mask data.
*/
-void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
- bool need_pmap, bool need_mask)
+void BKE_sculpt_update_mesh_elements(
+ Depsgraph *depsgraph, Scene *scene, Sculpt *sd, Object *ob,
+ bool need_pmap, bool need_mask)
{
- DerivedMesh *dm;
+ /* TODO(sergey): Make sure ob points to an original object. This is what it
+ * is supposed to be pointing to. The issue is, currently draw code takes
+ * care of PBVH creation, even though this is something up to dependency
+ * graph.
+ * Probably, we need to being back logic which was checking for sculpt mode
+ * and (re)create PBVH if needed in that case, similar to how DerivedMesh
+ * was handling this.
+ */
+ ob = DEG_get_original_object(ob);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
ss->modifiers_active = sculpt_modifiers_active(scene, sd, ob);
@@ -895,13 +1108,13 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ Mesh *me_eval = mesh_get_eval_final(depsgraph, scene, ob_eval, CD_MASK_BAREMESH);
/* VWPaint require mesh info for loop lookup, so require sculpt mode here */
if (mmd && ob->mode & OB_MODE_SCULPT) {
ss->multires = mmd;
- ss->totvert = dm->getNumVerts(dm);
- ss->totpoly = dm->getNumPolys(dm);
+ ss->totvert = me_eval->totvert;
+ ss->totpoly = me_eval->totpoly;
ss->mvert = NULL;
ss->mpoly = NULL;
ss->mloop = NULL;
@@ -916,22 +1129,34 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
}
- ss->pbvh = dm->getPBVH(ob, dm);
- ss->pmap = (need_pmap && dm->getPolyMap) ? dm->getPolyMap(ob, dm) : NULL;
+ ss->subdiv_ccg = me_eval->runtime.subdiv_ccg;
+
+ PBVH *pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
+ BLI_assert(pbvh == ss->pbvh);
+ UNUSED_VARS_NDEBUG(pbvh);
+ MEM_SAFE_FREE(ss->pmap);
+ MEM_SAFE_FREE(ss->pmap_mem);
+ if (need_pmap && ob->type == OB_MESH) {
+ BKE_mesh_vert_poly_map_create(
+ &ss->pmap, &ss->pmap_mem,
+ me->mpoly, me->mloop,
+ me->totvert, me->totpoly, me->totloop);
+ }
pbvh_show_diffuse_color_set(ss->pbvh, ss->show_diffuse_color);
pbvh_show_mask_set(ss->pbvh, ss->show_mask);
if (ss->modifiers_active) {
if (!ss->orig_cos) {
+ Object *object_orig = DEG_get_original_object(ob);
int a;
BKE_sculptsession_free_deformMats(ss);
ss->orig_cos = (ss->kb) ? BKE_keyblock_convert_to_vertcos(ob, ss->kb) : BKE_mesh_vertexCos_get(me, NULL);
- BKE_crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos);
- BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
+ BKE_crazyspace_build_sculpt(depsgraph, scene, object_orig, &ss->deform_imats, &ss->deform_cos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos, me->totvert);
for (a = 0; a < me->totvert; ++a) {
invert_m3(ss->deform_imats[a]);
@@ -955,7 +1180,7 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
if (vertCos) {
if (!pbvh_deformed) {
/* apply shape keys coordinates to PBVH */
- BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos, me->totvert);
}
if (ss->deform_cos == NULL) {
ss->deform_cos = vertCos;
@@ -966,6 +1191,9 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
}
}
}
+
+ /* 2.8x - avoid full mesh update! */
+ BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_SCULPT_COORDS);
}
int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
@@ -1041,18 +1269,9 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
{
- Sculpt *sd = scene->toolsettings->sculpt;
- if (sd == NULL) {
- sd = scene->toolsettings->sculpt = MEM_callocN(sizeof(Sculpt), __func__);
-
- /* Turn on X plane mirror symmetry by default */
- sd->paint.symmetry_flags |= PAINT_SYMM_X;
- sd->paint.flags |= PAINT_SHOW_BRUSH;
-
- /* Make sure at least dyntopo subdivision is enabled */
- sd->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
- }
+ BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->sculpt);
+ Sculpt *sd = scene->toolsettings->sculpt;
if (!sd->detail_size) {
sd->detail_size = 12;
}
@@ -1074,3 +1293,123 @@ void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene)
sd->paint.tile_offset[2] = 1.0f;
}
}
+
+static bool check_sculpt_object_deformed(Object *object, const bool for_construction)
+{
+ bool deformed = false;
+
+ /* Active modifiers means extra deformation, which can't be handled correct
+ * on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
+ * stuff and show final evaluated mesh so user would see actual object shape.
+ */
+ deformed |= object->sculpt->modifiers_active;
+
+ if (for_construction) {
+ deformed |= object->sculpt->kb != NULL;
+ }
+ else {
+ /* As in case with modifiers, we can't synchronize deformation made against
+ * PBVH and non-locked keyblock, so also use PBVH only for brushes and
+ * final DM to give final result to user.
+ */
+ deformed |= object->sculpt->kb && (object->shapeflag & OB_SHAPE_LOCK) == 0;
+ }
+
+ return deformed;
+}
+
+static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
+{
+ PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_build_bmesh(pbvh, ob->sculpt->bm,
+ ob->sculpt->bm_smooth_shading,
+ ob->sculpt->bm_log, ob->sculpt->cd_vert_node_offset,
+ ob->sculpt->cd_face_node_offset);
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+ return pbvh;
+}
+
+static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
+{
+ Mesh *me = BKE_object_get_original_mesh(ob);
+ const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
+ PBVH *pbvh = BKE_pbvh_new();
+
+ MLoopTri *looptri = MEM_malloc_arrayN(
+ looptris_num, sizeof(*looptri), __func__);
+
+ BKE_mesh_recalc_looptri(
+ me->mloop, me->mpoly,
+ me->mvert,
+ me->totloop, me->totpoly,
+ looptri);
+
+ BKE_pbvh_build_mesh(
+ pbvh,
+ me->mpoly, me->mloop,
+ me->mvert, me->totvert, &me->vdata,
+ looptri, looptris_num);
+
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+
+ const bool is_deformed = check_sculpt_object_deformed(ob, true);
+ if (is_deformed && me_eval_deform != NULL) {
+ int totvert;
+ float (*v_cos)[3] = BKE_mesh_vertexCos_get(me_eval_deform, &totvert);
+ BKE_pbvh_apply_vertCos(pbvh, v_cos, totvert);
+ MEM_freeN(v_cos);
+ }
+
+ return pbvh;
+}
+
+static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ PBVH *pbvh = BKE_pbvh_new();
+ BKE_pbvh_build_grids(
+ pbvh,
+ subdiv_ccg->grids, subdiv_ccg->num_grids,
+ &key,
+ (void **)subdiv_ccg->grid_faces,
+ subdiv_ccg->grid_flag_mats,
+ subdiv_ccg->grid_hidden);
+ pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
+ return pbvh;
+}
+
+PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
+{
+ if (ob == NULL || ob->sculpt == NULL) {
+ return NULL;
+ }
+ PBVH *pbvh = ob->sculpt->pbvh;
+ if (pbvh != NULL) {
+ /* Nothing to do, PBVH is already up to date. */
+ return pbvh;
+ }
+
+ if (ob->sculpt->bm != NULL) {
+ /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */
+ pbvh = build_pbvh_for_dynamic_topology(ob);
+ }
+ else {
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ Mesh *mesh_eval = object_eval->data;
+ if (mesh_eval->runtime.subdiv_ccg != NULL) {
+ pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg);
+ }
+ else if (ob->type == OB_MESH) {
+ Mesh *me_eval_deform = mesh_get_eval_deform(
+ depsgraph, DEG_get_evaluated_scene(depsgraph), ob, CD_MASK_BAREMESH);
+ pbvh = build_pbvh_from_regular_mesh(ob, me_eval_deform);
+ }
+ }
+
+ ob->sculpt->pbvh = pbvh;
+ return pbvh;
+}
diff --git a/source/blender/blenkernel/intern/paint_toolslots.c b/source/blender/blenkernel/intern/paint_toolslots.c
new file mode 100644
index 00000000000..92e42a0a468
--- /dev/null
+++ b/source/blender/blenkernel/intern/paint_toolslots.c
@@ -0,0 +1,140 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/paint_toolslots.c
+ * \ingroup bke
+ */
+
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_brush_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_brush.h"
+#include "BKE_paint.h"
+
+void BKE_paint_toolslots_len_ensure(Paint *paint, int len)
+{
+ /* Tool slots are 'uchar'. */
+ BLI_assert(len <= UCHAR_MAX);
+ if (paint->tool_slots_len < len) {
+ paint->tool_slots = MEM_recallocN(paint->tool_slots, sizeof(*paint->tool_slots) * len);
+ paint->tool_slots_len = len;
+ }
+}
+
+static void paint_toolslots_init(Main *bmain, Paint *paint)
+{
+ if (paint == NULL) {
+ return;
+ }
+ const eObjectMode ob_mode = paint->runtime.ob_mode;
+ BLI_assert(paint->runtime.tool_offset && ob_mode);
+ for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) {
+ if (brush->ob_mode & ob_mode) {
+ const int slot_index = BKE_brush_tool_get(brush, paint);
+ BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
+ if (paint->tool_slots[slot_index].brush == NULL) {
+ paint->tool_slots[slot_index].brush = brush;
+ id_us_plus(&brush->id);
+ }
+ }
+ }
+}
+
+void BKE_paint_toolslots_init_from_main(struct Main *bmain)
+{
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ ToolSettings *ts = scene->toolsettings;
+ paint_toolslots_init(bmain, &ts->imapaint.paint);
+ paint_toolslots_init(bmain, &ts->sculpt->paint);
+ paint_toolslots_init(bmain, &ts->vpaint->paint);
+ paint_toolslots_init(bmain, &ts->wpaint->paint);
+ paint_toolslots_init(bmain, &ts->gp_paint->paint);
+ }
+}
+
+
+void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush)
+{
+ const uint tool_offset = paint->runtime.tool_offset;
+ UNUSED_VARS_NDEBUG(tool_offset);
+ BLI_assert(tool_offset != 0);
+ const int slot_index = BKE_brush_tool_get(brush, paint);
+ BKE_paint_toolslots_len_ensure(paint, slot_index + 1);
+ PaintToolSlot *tslot = &paint->tool_slots[slot_index];
+ id_us_plus(&brush->id);
+ id_us_min(&tslot->brush->id);
+ tslot->brush = brush;
+}
+
+void BKE_paint_toolslots_brush_update(Paint *paint)
+{
+ if (paint->brush == NULL) {
+ return;
+ }
+ BKE_paint_toolslots_brush_update_ex(paint, paint->brush);
+}
+
+/**
+ * Run this to ensure brush types are set for each slot on entering modes
+ * (for new scenes for example).
+ */
+void BKE_paint_toolslots_brush_validate(Main *bmain, Paint *paint)
+{
+ /* Clear slots with invalid slots or mode (unlikely but possible). */
+ const uint tool_offset = paint->runtime.tool_offset;
+ UNUSED_VARS_NDEBUG(tool_offset);
+ const eObjectMode ob_mode = paint->runtime.ob_mode;
+ BLI_assert(tool_offset && ob_mode);
+ for (int i = 0; i < paint->tool_slots_len; i++) {
+ PaintToolSlot *tslot = &paint->tool_slots[i];
+ if (tslot->brush) {
+ if ((i != BKE_brush_tool_get(tslot->brush, paint)) ||
+ (tslot->brush->ob_mode & ob_mode) == 0)
+ {
+ id_us_min(&tslot->brush->id);
+ tslot->brush = NULL;
+ }
+ }
+ }
+
+ /* Unlikely but possible the active brush is not currently using a slot. */
+ BKE_paint_toolslots_brush_update(paint);
+
+ /* Fill slots from brushes. */
+ paint_toolslots_init(bmain, paint);
+}
+
+Brush *BKE_paint_toolslots_brush_get(Paint *paint, int slot_index)
+{
+ if (slot_index < paint->tool_slots_len) {
+ PaintToolSlot *tslot = &paint->tool_slots[slot_index];
+ return tslot->brush;
+ }
+ return NULL;
+}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 40c0e1f8184..cec27b8f187 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -36,8 +36,8 @@
#include "MEM_guardedalloc.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
@@ -51,6 +51,7 @@
#include "BLI_noise.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_kdopbvh.h"
#include "BLI_kdtree.h"
#include "BLI_rand.h"
#include "BLI_task.h"
@@ -64,10 +65,10 @@
#include "BKE_boids.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
#include "BKE_colortools.h"
#include "BKE_effect.h"
#include "BKE_global.h"
-#include "BKE_group.h"
#include "BKE_main.h"
#include "BKE_lattice.h"
@@ -78,14 +79,17 @@
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_library_remap.h"
-#include "BKE_depsgraph.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_cdderivedmesh.h" /* for weight_to_rgb() */
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_deform.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
#include "RE_render_ext.h"
#include "particle_private.h"
@@ -96,19 +100,19 @@ float PSYS_FRAND_BASE[PSYS_FRAND_COUNT];
void psys_init_rng(void)
{
- int i;
- BLI_srandom(5831); /* arbitrary */
- for (i = 0; i < PSYS_FRAND_COUNT; ++i) {
- PSYS_FRAND_BASE[i] = BLI_frand();
- PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rand();
- PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rand();
+ RNG *rng = BLI_rng_new_srandom(5831); /* arbitrary */
+ for (int i = 0; i < PSYS_FRAND_COUNT; ++i) {
+ PSYS_FRAND_BASE[i] = BLI_rng_get_float(rng);
+ PSYS_FRAND_SEED_OFFSET[i] = (unsigned int)BLI_rng_get_int(rng);
+ PSYS_FRAND_SEED_MULTIPLIER[i] = (unsigned int)BLI_rng_get_int(rng);
}
+ BLI_rng_free(rng);
}
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
-static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
- int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
+static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
+ int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys)
@@ -228,31 +232,15 @@ void psys_set_current_num(Object *ob, int index)
}
}
-#if 0 /* UNUSED */
-Object *psys_find_object(Scene *scene, ParticleSystem *psys)
-{
- Base *base;
- ParticleSystem *tpsys;
-
- for (base = scene->base.first; base; base = base->next) {
- for (tpsys = base->object->particlesystem.first; psys; psys = psys->next) {
- if (tpsys == psys)
- return base->object;
- }
- }
-
- return NULL;
-}
-#endif
-
struct LatticeDeformData *psys_create_lattice_deform_data(ParticleSimulationData *sim)
{
struct LatticeDeformData *lattice_deform_data = NULL;
- if (psys_in_edit_mode(sim->scene, sim->psys) == 0) {
+ if (psys_in_edit_mode(sim->depsgraph, sim->psys) == 0) {
Object *lattice = NULL;
ModifierData *md = (ModifierData *)psys_get_modifier(sim->ob, sim->psys);
- int mode = G.is_rendering ? eModifierMode_Render : eModifierMode_Realtime;
+ bool for_render = DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER;
+ int mode = for_render ? eModifierMode_Render : eModifierMode_Realtime;
for (; md; md = md->next) {
if (md->type == eModifierType_Lattice) {
@@ -285,10 +273,40 @@ void psys_enable_all(Object *ob)
for (; psys; psys = psys->next)
psys->flag &= ~PSYS_DISABLED;
}
-bool psys_in_edit_mode(Scene *scene, ParticleSystem *psys)
+
+ParticleSystem *psys_orig_get(ParticleSystem *psys)
+{
+ if (psys->orig_psys == NULL) {
+ return psys;
+ }
+ return psys->orig_psys;
+}
+
+static PTCacheEdit *psys_orig_edit_get(ParticleSystem *psys)
+{
+ if (psys->orig_psys == NULL) {
+ return psys->edit;
+ }
+ return psys->orig_psys->edit;
+}
+
+bool psys_in_edit_mode(Depsgraph *depsgraph, const ParticleSystem *psys)
{
- return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit) && !psys->renderdata);
+ const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ if (view_layer->basact == NULL) {
+ /* TODO(sergey): Needs double-check with multi-object edit. */
+ return false;
+ }
+ const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
+ const Object *object = view_layer->basact->object;
+ if (object->mode != OB_MODE_PARTICLE_EDIT) {
+ return false;
+ }
+ const ParticleSystem *psys_orig = psys_orig_get((ParticleSystem *)psys);
+ return (psys_orig->edit || psys->pointcache->edit) &&
+ (use_render_params == false);
}
+
bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSystemModifierData *psmd;
@@ -297,7 +315,7 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_
return 0;
psmd = psys_get_modifier(ob, psys);
- if (psys->renderdata || use_render_params) {
+ if (use_render_params) {
if (!(psmd->modifier.mode & eModifierMode_Render))
return 0;
}
@@ -315,68 +333,84 @@ bool psys_check_edited(ParticleSystem *psys)
return (psys->pointcache->edit && psys->pointcache->edit->edited);
}
+void psys_find_group_weights(ParticleSettings *part)
+{
+ /* Find object pointers based on index. If the collection is linked from
+ * another library linking may not have the object pointers available on
+ * file load, so we have to retrieve them later. See T49273. */
+ const ListBase dup_group_objects = BKE_collection_object_cache_get(part->dup_group);
+
+ for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
+ if (dw->ob == NULL) {
+ Base *base = BLI_findlink(&dup_group_objects, dw->index);
+ if (base != NULL) {
+ dw->ob = base->object;
+ }
+ }
+ }
+}
+
void psys_check_group_weights(ParticleSettings *part)
{
ParticleDupliWeight *dw, *tdw;
- GroupObject *go;
- int current = 0;
- if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) {
- /* First try to find NULL objects from their index,
- * and remove all weights that don't have an object in the group. */
- dw = part->dupliweights.first;
- while (dw) {
- if (dw->ob == NULL || !BKE_group_object_exists(part->dup_group, dw->ob)) {
- go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
- if (go) {
- dw->ob = go->ob;
- }
- else {
- tdw = dw->next;
- BLI_freelinkN(&part->dupliweights, dw);
- dw = tdw;
- }
- }
- else {
- dw = dw->next;
- }
- }
+ if (part->ren_as != PART_DRAW_GR || !part->dup_group) {
+ BLI_freelistN(&part->dupliweights);
+ return;
+ }
- /* then add objects in the group to new list */
- go = part->dup_group->gobject.first;
- while (go) {
- dw = part->dupliweights.first;
- while (dw && dw->ob != go->ob)
- dw = dw->next;
-
- if (!dw) {
- dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
- dw->ob = go->ob;
- dw->count = 1;
- BLI_addtail(&part->dupliweights, dw);
- }
+ /* Find object pointers. */
+ psys_find_group_weights(part);
- go = go->next;
+ /* Remove NULL objects, that were removed from the collection. */
+ dw = part->dupliweights.first;
+ while (dw) {
+ if (dw->ob == NULL || !BKE_collection_has_object_recursive(part->dup_group, dw->ob)) {
+ tdw = dw->next;
+ BLI_freelinkN(&part->dupliweights, dw);
+ dw = tdw;
+ }
+ else {
+ dw = dw->next;
}
+ }
+ /* Add new objects in the collection. */
+ int index = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object)
+ {
dw = part->dupliweights.first;
- for (; dw; dw = dw->next) {
- if (dw->flag & PART_DUPLIW_CURRENT) {
- current = 1;
- break;
- }
+ while (dw && dw->ob != object) {
+ dw = dw->next;
}
- if (!current) {
- dw = part->dupliweights.first;
- if (dw)
- dw->flag |= PART_DUPLIW_CURRENT;
+ if (!dw) {
+ dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
+ dw->ob = object;
+ dw->count = 1;
+ BLI_addtail(&part->dupliweights, dw);
}
+
+ dw->index = index++;
}
- else {
- BLI_freelistN(&part->dupliweights);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ /* Ensure there is an element marked as current. */
+ int current = 0;
+ for (dw = part->dupliweights.first; dw; dw = dw->next) {
+ if (dw->flag & PART_DUPLIW_CURRENT) {
+ current = 1;
+ break;
+ }
+ }
+
+ if (!current) {
+ dw = part->dupliweights.first;
+ if (dw)
+ dw->flag |= PART_DUPLIW_CURRENT;
}
}
+
int psys_uses_gravity(ParticleSimulationData *sim)
{
return sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY && sim->psys->part && sim->psys->part->effector_weights->global_gravity != 0.0f;
@@ -447,13 +481,13 @@ void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics)
}
}
- if (psys->hair_in_dm)
- psys->hair_in_dm->release(psys->hair_in_dm);
- psys->hair_in_dm = NULL;
+ if (psys->hair_in_mesh)
+ BKE_id_free(NULL, psys->hair_in_mesh);
+ psys->hair_in_mesh = NULL;
- if (psys->hair_out_dm)
- psys->hair_out_dm->release(psys->hair_out_dm);
- psys->hair_out_dm = NULL;
+ if (psys->hair_out_mesh)
+ BKE_id_free(NULL, psys->hair_out_mesh);
+ psys->hair_out_mesh = NULL;
}
void free_keyed_keys(ParticleSystem *psys)
{
@@ -601,213 +635,62 @@ void psys_free(Object *ob, ParticleSystem *psys)
if (psys->fluid_springs)
MEM_freeN(psys->fluid_springs);
- pdEndEffectors(&psys->effectors);
+ BKE_effectors_free(psys->effectors);
if (psys->pdd) {
psys_free_pdd(psys);
MEM_freeN(psys->pdd);
}
- MEM_freeN(psys);
- }
-}
-
-/************************************************/
-/* Rendering */
-/************************************************/
-/* these functions move away particle data and bring it back after
- * rendering, to make different render settings possible without
- * removing the previous data. this should be solved properly once */
-
-void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset)
-{
- ParticleRenderData *data;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
-
- if (psys->renderdata)
- return;
-
- data = MEM_callocN(sizeof(ParticleRenderData), "ParticleRenderData");
-
- data->child = psys->child;
- data->totchild = psys->totchild;
- data->pathcache = psys->pathcache;
- data->pathcachebufs.first = psys->pathcachebufs.first;
- data->pathcachebufs.last = psys->pathcachebufs.last;
- data->totcached = psys->totcached;
- data->childcache = psys->childcache;
- data->childcachebufs.first = psys->childcachebufs.first;
- data->childcachebufs.last = psys->childcachebufs.last;
- data->totchildcache = psys->totchildcache;
+ BKE_particle_batch_cache_free(psys);
- if (psmd->dm_final) {
- data->dm = CDDM_copy_with_tessface(psmd->dm_final);
- }
- data->totdmvert = psmd->totdmvert;
- data->totdmedge = psmd->totdmedge;
- data->totdmface = psmd->totdmface;
-
- psys->child = NULL;
- psys->pathcache = NULL;
- psys->childcache = NULL;
- psys->totchild = psys->totcached = psys->totchildcache = 0;
- BLI_listbase_clear(&psys->pathcachebufs);
- BLI_listbase_clear(&psys->childcachebufs);
-
- copy_m4_m4(data->winmat, winmat);
- mul_m4_m4m4(data->viewmat, viewmat, ob->obmat);
- mul_m4_m4m4(data->mat, winmat, data->viewmat);
- data->winx = winx;
- data->winy = winy;
-
- data->timeoffset = timeoffset;
-
- psys->renderdata = data;
-
- /* Hair can and has to be recalculated if everything isn't displayed. */
- if (psys->part->disp != 100 && ELEM(psys->part->type, PART_HAIR, PART_FLUID)) {
- psys->recalc |= PSYS_RECALC_RESET;
+ MEM_freeN(psys);
}
}
-void psys_render_restore(Object *ob, ParticleSystem *psys)
+void psys_copy_particles(ParticleSystem *psys_dst, ParticleSystem *psys_src)
{
- ParticleRenderData *data;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- float render_disp = psys_get_current_display_percentage(psys);
- float disp;
-
- data = psys->renderdata;
- if (!data)
- return;
-
- if (data->elems)
- MEM_freeN(data->elems);
-
- if (psmd->dm_final) {
- psmd->dm_final->needsFree = 1;
- psmd->dm_final->release(psmd->dm_final);
- }
- if (psmd->dm_deformed) {
- psmd->dm_deformed->needsFree = 1;
- psmd->dm_deformed->release(psmd->dm_deformed);
- psmd->dm_deformed = NULL;
- }
-
- psys_free_path_cache(psys, NULL);
-
- if (psys->child) {
- MEM_freeN(psys->child);
- psys->child = 0;
- psys->totchild = 0;
- }
-
- psys->child = data->child;
- psys->totchild = data->totchild;
- psys->pathcache = data->pathcache;
- psys->pathcachebufs.first = data->pathcachebufs.first;
- psys->pathcachebufs.last = data->pathcachebufs.last;
- psys->totcached = data->totcached;
- psys->childcache = data->childcache;
- psys->childcachebufs.first = data->childcachebufs.first;
- psys->childcachebufs.last = data->childcachebufs.last;
- psys->totchildcache = data->totchildcache;
-
- psmd->dm_final = data->dm;
- psmd->totdmvert = data->totdmvert;
- psmd->totdmedge = data->totdmedge;
- psmd->totdmface = data->totdmface;
- psmd->flag &= ~eParticleSystemFlag_psys_updated;
-
- if (psmd->dm_final) {
- if (!psmd->dm_final->deformedOnly) {
- if (ob->derivedDeform) {
- psmd->dm_deformed = CDDM_copy(ob->derivedDeform);
- }
- else {
- psmd->dm_deformed = CDDM_from_mesh((Mesh *)ob->data);
- }
- DM_ensure_tessface(psmd->dm_deformed);
- }
- psys_calc_dmcache(ob, psmd->dm_final, psmd->dm_deformed, psys);
- }
-
- MEM_freeN(data);
- psys->renderdata = NULL;
-
- /* restore particle display percentage */
- disp = psys_get_current_display_percentage(psys);
-
- if (disp != render_disp) {
- /* Hair can and has to be recalculated if everything isn't displayed. */
- if (ELEM(psys->part->type, PART_HAIR, PART_FLUID)) {
- psys->recalc |= PSYS_RECALC_RESET;
+ /* Free existing particles. */
+ if (psys_dst->particles != psys_src->particles) {
+ psys_free_particles(psys_dst);
+ }
+ if (psys_dst->child != psys_src->child) {
+ psys_free_children(psys_dst);
+ }
+ /* Restore counters. */
+ psys_dst->totpart = psys_src->totpart;
+ psys_dst->totchild = psys_src->totchild;
+ /* Copy particles and children. */
+ psys_dst->particles = MEM_dupallocN(psys_src->particles);
+ psys_dst->child = MEM_dupallocN(psys_src->child);
+ if (psys_dst->part->type == PART_HAIR) {
+ ParticleData *pa;
+ int p;
+ for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
+ pa->hair = MEM_dupallocN(pa->hair);
}
- else {
- PARTICLE_P;
-
- LOOP_PARTICLES {
- if (psys_frand(psys, p) > disp)
- pa->flag |= PARS_NO_DISP;
- else
- pa->flag &= ~PARS_NO_DISP;
- }
- }
- }
-}
-
-bool psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float *params)
-{
- ParticleRenderData *data;
- ParticleRenderElem *elem;
- float x, w, scale, alpha, lambda, t, scalemin, scalemax;
- int b;
-
- if (!(psys->renderdata && (psys->part->simplify_flag & PART_SIMPLIFY_ENABLE)))
- return false;
-
- data = psys->renderdata;
- if (!data->do_simplify)
- return false;
- b = (data->index_mf_to_mpoly) ? DM_origindex_mface_mpoly(data->index_mf_to_mpoly, data->index_mp_to_orig, cpa->num) : cpa->num;
- if (b == ORIGINDEX_NONE) {
- return false;
- }
-
- elem = &data->elems[b];
-
- lambda = elem->lambda;
- t = elem->t;
- scalemin = elem->scalemin;
- scalemax = elem->scalemax;
-
- if (!elem->reduce) {
- scale = scalemin;
- alpha = 1.0f;
}
- else {
- x = (elem->curchild + 0.5f) / elem->totchild;
- if (x < lambda - t) {
- scale = scalemax;
- alpha = 1.0f;
+ if (psys_dst->particles && (psys_dst->particles->keys || psys_dst->particles->boid)) {
+ ParticleKey *key = psys_dst->particles->keys;
+ BoidParticle *boid = psys_dst->particles->boid;
+ ParticleData *pa;
+ int p;
+ if (key != NULL) {
+ key = MEM_dupallocN(key);
}
- else if (x >= lambda + t) {
- scale = scalemin;
- alpha = 0.0f;
+ if (boid != NULL) {
+ boid = MEM_dupallocN(boid);
}
- else {
- w = (lambda + t - x) / (2.0f * t);
- scale = scalemin + (scalemax - scalemin) * w;
- alpha = w;
+ for (p = 0, pa = psys_dst->particles; p < psys_dst->totpart; p++, pa++) {
+ if (boid != NULL) {
+ pa->boid = boid++;
+ }
+ if (key != NULL) {
+ pa->keys = key;
+ key += pa->totkey;
+ }
}
}
-
- params[0] = scale;
- params[1] = alpha;
-
- elem->curchild++;
-
- return 1;
}
/************************************************/
@@ -859,7 +742,7 @@ void psys_interpolate_particle(short type, ParticleKey keys[4], float dt, Partic
typedef struct ParticleInterpolationData {
HairKey *hkey[2];
- DerivedMesh *dm;
+ Mesh *mesh;
MVert *mvert[2];
int keyed;
@@ -993,8 +876,8 @@ static void init_particle_interpolation(Object *ob, ParticleSystem *psys, Partic
pind->birthtime = key->time;
pind->dietime = (key + pa->totkey - 1)->time;
- if (pind->dm) {
- pind->mvert[0] = CDDM_get_vert(pind->dm, pa->hair_index);
+ if (pind->mesh) {
+ pind->mvert[0] = &pind->mesh->mvert[pa->hair_index];
pind->mvert[1] = pind->mvert[0] + 1;
}
}
@@ -1103,7 +986,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
edit_to_particle(keys + 1, pind->ekey[0]);
edit_to_particle(keys + 2, pind->ekey[1]);
}
- else if (pind->dm) {
+ else if (pind->mesh) {
pind->mvert[0] = pind->mvert[1] - 1;
mvert_to_particle(keys + 1, pind->mvert[0], pind->hkey[0]);
mvert_to_particle(keys + 2, pind->mvert[1], pind->hkey[1]);
@@ -1128,7 +1011,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
else
edit_to_particle(keys, pind->ekey[0]);
}
- else if (pind->dm) {
+ else if (pind->mesh) {
if (pind->hkey[0] != pa->hair)
mvert_to_particle(keys, pind->mvert[0] - 1, pind->hkey[0] - 1);
else
@@ -1147,7 +1030,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
else
edit_to_particle(keys + 3, pind->ekey[1]);
}
- else if (pind->dm) {
+ else if (pind->mesh) {
if (pind->hkey[1] != pa->hair + pa->totkey - 1)
mvert_to_particle(keys + 3, pind->mvert[1] + 1, pind->hkey[1] + 1);
else
@@ -1216,7 +1099,7 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
/* interpolate a location on a face based on face coordinates */
void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*orcodata)[3],
float w[4], float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
float *v1 = 0, *v2 = 0, *v3 = 0, *v4 = 0;
float e1[3], e2[3], s1, s2, t1, t2;
@@ -1314,21 +1197,13 @@ void psys_interpolate_face(MVert *mvert, MFace *mface, MTFace *tface, float (*or
o4 = orcodata[mface->v4];
interp_v3_v3v3v3v3(orco, o1, o2, o3, o4, w);
-
- if (ornor)
- normal_quad_v3(ornor, o1, o2, o3, o4);
}
else {
interp_v3_v3v3v3(orco, o1, o2, o3, w);
-
- if (ornor)
- normal_tri_v3(ornor, o1, o2, o3);
}
}
else {
copy_v3_v3(orco, vec);
- if (ornor && nor)
- copy_v3_v3(ornor, nor);
}
}
}
@@ -1381,7 +1256,7 @@ void psys_interpolate_mcol(const MCol *mcol, int quad, const float w[4], MCol *m
}
}
-static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index, const float fw[4], const float *values)
+static float psys_interpolate_value_from_verts(Mesh *mesh, short from, int index, const float fw[4], const float *values)
{
if (values == 0 || index == -1)
return 0.0;
@@ -1392,7 +1267,7 @@ static float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int
case PART_FROM_FACE:
case PART_FROM_VOLUME:
{
- MFace *mf = dm->getTessFaceData(dm, index, CD_MFACE);
+ MFace *mf = &mesh->mface[index];
return interpolate_particle_value(values[mf->v1], values[mf->v2], values[mf->v3], values[mf->v4], fw, mf->v4);
}
@@ -1442,7 +1317,7 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
* \return the DM tessface index.
*/
int psys_particle_dm_face_lookup(
- DerivedMesh *dm_final, DerivedMesh *dm_deformed,
+ Mesh *mesh_final, Mesh *mesh_original,
int findex_orig, const float fw[4], struct LinkNode **poly_nodes)
{
MFace *mtessface_final;
@@ -1454,36 +1329,36 @@ int psys_particle_dm_face_lookup(
const int *index_mf_to_mpoly = NULL;
const int *index_mp_to_orig = NULL;
- const int totface_final = dm_final->getNumTessFaces(dm_final);
- const int totface_deformed = dm_deformed ? dm_deformed->getNumTessFaces(dm_deformed) : totface_final;
+ const int totface_final = mesh_final->totface;
+ const int totface_deformed = mesh_original ? mesh_original->totface : totface_final;
if (ELEM(0, totface_final, totface_deformed)) {
return DMCACHE_NOTFOUND;
}
- index_mf_to_mpoly = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX);
- index_mp_to_orig = dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX);
+ index_mf_to_mpoly = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
+ index_mp_to_orig = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
BLI_assert(index_mf_to_mpoly);
- if (dm_deformed) {
- index_mf_to_mpoly_deformed = dm_deformed->getTessFaceDataArray(dm_deformed, CD_ORIGINDEX);
+ if (mesh_original) {
+ index_mf_to_mpoly_deformed = CustomData_get_layer(&mesh_original->fdata, CD_ORIGINDEX);
}
else {
- BLI_assert(dm_final->deformedOnly);
+ BLI_assert(mesh_final->runtime.deformed_only);
index_mf_to_mpoly_deformed = index_mf_to_mpoly;
}
BLI_assert(index_mf_to_mpoly_deformed);
pindex_orig = index_mf_to_mpoly_deformed[findex_orig];
- if (dm_deformed == NULL) {
- dm_deformed = dm_final;
+ if (mesh_original == NULL) {
+ mesh_original = mesh_final;
}
index_mf_to_mpoly_deformed = NULL;
- mtessface_final = dm_final->getTessFaceArray(dm_final);
- osface_final = dm_final->getTessFaceDataArray(dm_final, CD_ORIGSPACE);
+ mtessface_final = mesh_final->mface;
+ osface_final = CustomData_get_layer(&mesh_final->fdata, CD_ORIGSPACE);
if (osface_final == NULL) {
/* Assume we don't need osface_final data, and we get a direct 1-1 mapping... */
@@ -1496,7 +1371,7 @@ int psys_particle_dm_face_lookup(
return DMCACHE_NOTFOUND;
}
}
- else if (findex_orig >= dm_deformed->getNumTessFaces(dm_deformed)) {
+ else if (findex_orig >= mesh_original->totface) {
return DMCACHE_NOTFOUND; /* index not in the original mesh */
}
@@ -1525,7 +1400,7 @@ int psys_particle_dm_face_lookup(
else { /* if we have no node, try every face */
for (int findex_dst = 0; findex_dst < totface_final; findex_dst++) {
/* If current tessface from 'final' DM and orig tessface (given by index) map to the same orig poly... */
- if (DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) {
+ if (BKE_mesh_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) {
faceuv = osface_final[findex_dst].uv;
/* check that this intersects - Its possible this misses :/ -
@@ -1545,22 +1420,22 @@ int psys_particle_dm_face_lookup(
return DMCACHE_NOTFOUND;
}
-static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache, const float fw[4], float UNUSED(foffset), int *mapindex, float mapfw[4])
+static int psys_map_index_on_dm(Mesh *mesh, int from, int index, int index_dmcache, const float fw[4], float UNUSED(foffset), int *mapindex, float mapfw[4])
{
if (index < 0)
return 0;
- if (dm->deformedOnly || index_dmcache == DMCACHE_ISCHILD) {
+ if (mesh->runtime.deformed_only || index_dmcache == DMCACHE_ISCHILD) {
/* for meshes that are either only deformed or for child particles, the
* index and fw do not require any mapping, so we can directly use it */
if (from == PART_FROM_VERT) {
- if (index >= dm->getNumVerts(dm))
+ if (index >= mesh->totvert)
return 0;
*mapindex = index;
}
else { /* FROM_FACE/FROM_VOLUME */
- if (index >= dm->getNumTessFaces(dm))
+ if (index >= mesh->totface)
return 0;
*mapindex = index;
@@ -1572,7 +1447,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
* to their new location, which means a different index, and for faces
* also a new face interpolation weights */
if (from == PART_FROM_VERT) {
- if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > dm->getNumVerts(dm))
+ if (index_dmcache == DMCACHE_NOTFOUND || index_dmcache > mesh->totvert)
return 0;
*mapindex = index_dmcache;
@@ -1585,15 +1460,15 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
i = index_dmcache;
- if (i == DMCACHE_NOTFOUND || i >= dm->getNumTessFaces(dm))
+ if (i == DMCACHE_NOTFOUND || i >= mesh->totface)
return 0;
*mapindex = i;
/* modify the original weights to become
* weights for the derived mesh face */
- osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
- mface = dm->getTessFaceData(dm, i, CD_MFACE);
+ osface = CustomData_get_layer(&mesh->fdata, CD_ORIGSPACE);
+ mface = &mesh->mface[i];
if (osface == NULL)
mapfw[0] = mapfw[1] = mapfw[2] = mapfw[3] = 0.0f;
@@ -1606,32 +1481,31 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
}
/* interprets particle data to get a point on a mesh in object space */
-void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_dmcache,
+void psys_particle_on_dm(Mesh *mesh_final, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
float tmpnor[3], mapfw[4];
float (*orcodata)[3];
int mapindex;
- if (!psys_map_index_on_dm(dm_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
+ if (!psys_map_index_on_dm(mesh_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
if (vec) { vec[0] = vec[1] = vec[2] = 0.0; }
if (nor) { nor[0] = nor[1] = 0.0; nor[2] = 1.0; }
if (orco) { orco[0] = orco[1] = orco[2] = 0.0; }
- if (ornor) { ornor[0] = ornor[1] = 0.0; ornor[2] = 1.0; }
if (utan) { utan[0] = utan[1] = utan[2] = 0.0; }
if (vtan) { vtan[0] = vtan[1] = vtan[2] = 0.0; }
return;
}
- orcodata = dm_final->getVertDataArray(dm_final, CD_ORCO);
+ orcodata = CustomData_get_layer(&mesh_final->vdata, CD_ORCO);
if (from == PART_FROM_VERT) {
- dm_final->getVertCo(dm_final, mapindex, vec);
+ copy_v3_v3(vec, mesh_final->mvert[mapindex].co);
if (nor) {
- dm_final->getVertNo(dm_final, mapindex, nor);
+ normal_short_to_float_v3(nor, mesh_final->mvert[mapindex].no);
normalize_v3(nor);
}
@@ -1644,11 +1518,6 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d
}
}
- if (ornor) {
- dm_final->getVertNo(dm_final, mapindex, ornor);
- normalize_v3(ornor);
- }
-
if (utan && vtan) {
utan[0] = utan[1] = utan[2] = 0.0f;
vtan[0] = vtan[1] = vtan[2] = 0.0f;
@@ -1659,15 +1528,15 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d
MTFace *mtface;
MVert *mvert;
- mface = dm_final->getTessFaceData(dm_final, mapindex, CD_MFACE);
- mvert = dm_final->getVertDataArray(dm_final, CD_MVERT);
- mtface = CustomData_get_layer(&dm_final->faceData, CD_MTFACE);
+ mface = &mesh_final->mface[mapindex];
+ mvert = mesh_final->mvert;
+ mtface = mesh_final->mtface;
if (mtface)
mtface += mapindex;
if (from == PART_FROM_VOLUME) {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco, ornor);
+ psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
if (nor)
copy_v3_v3(nor, tmpnor);
@@ -1676,19 +1545,19 @@ void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_d
add_v3_v3(vec, tmpnor);
}
else
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco, ornor);
+ psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
}
}
-float psys_particle_value_from_verts(DerivedMesh *dm, short from, ParticleData *pa, float *values)
+float psys_particle_value_from_verts(Mesh *mesh, short from, ParticleData *pa, float *values)
{
float mapfw[4];
int mapindex;
- if (!psys_map_index_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
+ if (!psys_map_index_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, &mapindex, mapfw))
return 0.0f;
- return psys_interpolate_value_from_verts(dm, from, mapindex, mapfw, values);
+ return psys_interpolate_value_from_verts(mesh, from, mapindex, mapfw, values);
}
ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
@@ -1712,7 +1581,7 @@ ParticleSystemModifierData *psys_get_modifier(Object *ob, ParticleSystem *psys)
/* ready for future use */
static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index),
float *UNUSED(fuv), float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
/* TODO */
float zerovec[3] = {0.0f, 0.0f, 0.0f};
@@ -1731,9 +1600,6 @@ static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index),
if (orco) {
copy_v3_v3(orco, zerovec);
}
- if (ornor) {
- copy_v3_v3(ornor, zerovec);
- }
}
/************************************************/
/* Particles on emitter */
@@ -1776,9 +1642,9 @@ CustomDataMask psys_emitter_customdata_mask(ParticleSystem *psys)
void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int index, int index_dmcache,
float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
- float orco[3], float ornor[3])
+ float orco[3])
{
- if (psmd && psmd->dm_final) {
+ if (psmd && psmd->mesh_final) {
if (psmd->psys->part->distr == PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT) {
if (vec)
copy_v3_v3(vec, fuv);
@@ -1788,10 +1654,10 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
return;
}
/* we cant use the num_dmcache */
- psys_particle_on_dm(psmd->dm_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco, ornor);
+ psys_particle_on_dm(psmd->mesh_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco);
}
else
- psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco, ornor);
+ psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco);
}
/************************************************/
@@ -1813,7 +1679,7 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
return;
LOOP_PARTICLES {
- psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0, 0);
+ psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, state.co, 0, 0, 0, 0);
mul_m4_v3(sim->ob->obmat, state.co);
mul_mat3_m4_v3(sim->ob->obmat, state.vel);
@@ -1839,7 +1705,7 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
}
}
-int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time)
+int do_guides(Depsgraph *depsgraph, ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time)
{
CurveMapping *clumpcurve = (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) ? part->clumpcurve : NULL;
CurveMapping *roughcurve = (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) ? part->roughcurve : NULL;
@@ -1902,7 +1768,7 @@ int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, i
/* curve taper */
if (cu->taperobj)
- mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
+ mul_v3_fl(vec_to_point, BKE_displist_calc_taper(depsgraph, eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
else { /* curve size*/
if (cu->flag & CU_PATH_RADIUS) {
@@ -1970,7 +1836,7 @@ static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheK
copy_qt_qt(eff_key.rot, (ca - 1)->rot);
pd_point_from_particle(sim, sim->psys->particles + i, &eff_key, &epoint);
- pdDoEffectors(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
+ BKE_effectors_apply(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
mul_v3_fl(force, effector * powf((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) / (float)steps);
@@ -2004,7 +1870,7 @@ static void offset_child(ChildParticle *cpa, ParticleKey *par, float *par_rot, P
add_v3_v3(child->co, par->co);
}
-float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
+float *psys_cache_vgroup(Mesh *mesh, ParticleSystem *psys, int vgroup)
{
float *vg = 0;
@@ -2013,9 +1879,9 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup)
}
else if (psys->vgroup[vgroup]) {
- MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ MDeformVert *dvert = mesh->dvert;
if (dvert) {
- int totvert = dm->getNumVerts(dm), i;
+ int totvert = mesh->totvert, i;
vg = MEM_callocN(sizeof(float) * totvert, "vg_cache");
if (psys->vg_neg & (1 << vgroup)) {
for (i = 0; i < totvert; i++)
@@ -2041,7 +1907,7 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
int from = PART_FROM_FACE;
totparent = (int)(totchild * part->parents * 0.3f);
- if ((sim->psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
+ if (use_render_params && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* hard limit, workaround for it being ignored above */
@@ -2052,10 +1918,10 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
tree = BLI_kdtree_new(totparent);
for (p = 0, cpa = sim->psys->child; p < totparent; p++, cpa++) {
- psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
/* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */
- get_cpa_texture(sim->psmd->dm_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+ get_cpa_texture(sim->psmd->mesh_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
if (ptex.exist >= psys_frand(psys, p + 24)) {
BLI_kdtree_insert(tree, p, orco);
@@ -2065,7 +1931,7 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
BLI_kdtree_balance(tree);
for (; p < totchild; p++, cpa++) {
- psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco);
cpa->parent = BLI_kdtree_find_nearest(tree, orco, NULL);
}
@@ -2085,10 +1951,10 @@ static bool psys_thread_context_init_path(
psys_thread_context_init(ctx, sim);
/*---start figuring out what is actually wanted---*/
- if (psys_in_edit_mode(scene, psys)) {
+ if (psys_in_edit_mode(sim->depsgraph, psys)) {
ParticleEditSettings *pset = &scene->toolsettings->particle;
- if ((psys->renderdata == 0 && use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if ((use_render_params == 0) && (psys_orig_edit_get(psys) == NULL || pset->flag & PE_DRAW_PART) == 0)
totchild = 0;
segments = 1 << pset->draw_step;
@@ -2097,14 +1963,14 @@ static bool psys_thread_context_init_path(
if (totchild && part->childtype == PART_CHILD_FACES) {
totparent = (int)(totchild * part->parents * 0.3f);
- if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr)
+ if (use_render_params && part->child_nbr && part->ren_child_nbr)
totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
/* part->parents could still be 0 so we can't test with totparent */
between = 1;
}
- if (psys->renderdata || use_render_params)
+ if (use_render_params)
segments = 1 << part->ren_step;
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
@@ -2130,15 +1996,15 @@ static bool psys_thread_context_init_path(
psys->lattice_deform_data = psys_create_lattice_deform_data(&ctx->sim);
/* cache all relevant vertex groups if they exist */
- ctx->vg_length = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_LENGTH);
- ctx->vg_clump = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_CLUMP);
- ctx->vg_kink = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_KINK);
- ctx->vg_rough1 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH1);
- ctx->vg_rough2 = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGH2);
- ctx->vg_roughe = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_ROUGHE);
- ctx->vg_twist = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_TWIST);
+ ctx->vg_length = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_LENGTH);
+ ctx->vg_clump = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_CLUMP);
+ ctx->vg_kink = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_KINK);
+ ctx->vg_rough1 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH1);
+ ctx->vg_rough2 = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGH2);
+ ctx->vg_roughe = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_ROUGHE);
+ ctx->vg_twist = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_TWIST);
if (psys->part->flag & PART_CHILD_EFFECT)
- ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR);
+ ctx->vg_effector = psys_cache_vgroup(ctx->mesh, psys, PSYS_VG_EFFECTOR);
/* prepare curvemapping tables */
if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) {
@@ -2182,11 +2048,12 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
ParticleSystem *psys = ctx->sim.psys;
ParticleSettings *part = psys->part;
ParticleCacheKey **cache = psys->childcache;
- ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.scene, psys) && psys->edit ? psys->edit->pathcache : psys->pathcache;
+ PTCacheEdit *edit = psys_orig_edit_get(psys);
+ ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.depsgraph, psys) && edit ? edit->pathcache : psys->pathcache;
ParticleCacheKey *child, *key[4];
ParticleTexture ptex;
float *cpa_fuv = 0, *par_rot = 0, rot[4];
- float orco[3], ornor[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
+ float orco[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
float eff_length, eff_vec[3], weight[4];
int k, cpa_num;
short cpa_from;
@@ -2208,7 +2075,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
needupdate = 0;
w = 0;
while (w < 4 && cpa->pa[w] >= 0) {
- if (psys->edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) {
+ if (edit->points[cpa->pa[w]].flag & PEP_EDIT_RECALC) {
needupdate = 1;
break;
}
@@ -2282,20 +2149,20 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
- psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, ornor, 0, 0, orco, 0);
+ psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
mul_m4_v3(ob->obmat, co);
for (w = 0; w < 4; w++)
sub_v3_v3v3(off1[w], co, key[w]->co);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
}
else {
ParticleData *pa = psys->particles + cpa->parent;
float co[3];
if (ctx->editupdate) {
- if (!(psys->edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
+ if (!(edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
return;
memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
@@ -2320,13 +2187,13 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
: pa->num_dmcache;
/* XXX hack to avoid messed up particle num and subsequent crash (#40733) */
- if (cpa_num > ctx->sim.psmd->dm_final->getNumTessFaces(ctx->sim.psmd->dm_final))
+ if (cpa_num > ctx->sim.psmd->mesh_final->totface)
cpa_num = 0;
cpa_fuv = pa->fuv;
- psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, ornor, 0, 0, orco, 0);
+ psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->mesh_final, psys->part->from, pa, hairmat);
}
child_keys->segments = ctx->segments;
@@ -2432,9 +2299,9 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
BLI_listbase_clear(&modifiers);
psys_particle_on_emitter(ctx->sim.psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset,
- par_co, NULL, NULL, NULL, par_orco, NULL);
+ par_co, NULL, NULL, NULL, par_orco);
- psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par, par_orco);
+ psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, hairmat, child_keys, par, par_orco);
}
else
zero_v3(par_orco);
@@ -2576,7 +2443,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
ParticleSettings *part = psys->part;
ParticleCacheKey *ca, **cache;
- DerivedMesh *hair_dm = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_dm : NULL;
+ Mesh *hair_mesh = (psys->part->type == PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS) ? psys->hair_out_mesh : NULL;
ParticleKey result;
@@ -2592,7 +2459,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
- int segments = (int)pow(2.0, (double)((psys->renderdata || use_render_params) ? part->ren_step : part->draw_step));
+ int segments = (int)pow(2.0, (double)((use_render_params) ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float length, vec[3];
float *vg_effector = NULL;
@@ -2603,8 +2470,8 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if ((psys->flag & PSYS_HAIR_DONE || psys->flag & PSYS_KEYED || psys->pointcache) == 0)
return;
- if (psys_in_edit_mode(sim->scene, psys))
- if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
+ if (psys_in_edit_mode(sim->depsgraph, psys))
+ if ((psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
return;
keyed = psys->flag & PSYS_KEYED;
@@ -2621,15 +2488,15 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if ((psys->flag & PSYS_GLOBAL_HAIR) == 0) {
if ((psys->part->flag & PART_CHILD_EFFECT) == 0)
- vg_effector = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_EFFECTOR);
+ vg_effector = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_EFFECTOR);
if (!psys->totchild)
- vg_length = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_LENGTH);
+ vg_length = psys_cache_vgroup(psmd->mesh_final, psys, PSYS_VG_LENGTH);
}
/* ensure we have tessfaces to be used for mapping */
if (part->from != PART_FROM_VERT) {
- DM_ensure_tessface(psmd->dm_final);
+ BKE_mesh_tessface_ensure(psmd->mesh_final);
}
/*---first main loop: create all actual particles' paths---*/
@@ -2638,14 +2505,14 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f);
pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p));
if (vg_length)
- pa_length *= psys_particle_value_from_verts(psmd->dm_final, part->from, pa, vg_length);
+ pa_length *= psys_particle_value_from_verts(psmd->mesh_final, part->from, pa, vg_length);
}
pind.keyed = keyed;
pind.cache = baked ? psys->pointcache : NULL;
pind.epoint = NULL;
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
- pind.dm = hair_dm;
+ pind.mesh = hair_mesh;
memset(cache[p], 0, sizeof(*cache[p]) * (segments + 1));
@@ -2655,7 +2522,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
init_particle_interpolation(sim->ob, sim->psys, pa, &pind);
/* hairmat is needed for for non-hair particle too so we get proper rotations */
- psys_mat_hair_to_global(sim->ob, psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, psmd->mesh_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -2687,7 +2554,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
/* dynamic hair is in object space */
/* keyed and baked are already in global space */
- if (hair_dm)
+ if (hair_mesh)
mul_m4_v3(sim->ob->obmat, ca->co);
else if (!keyed && !baked && !(psys->flag & PSYS_GLOBAL_HAIR))
mul_m4_v3(hairmat, ca->co);
@@ -2710,7 +2577,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if ((psys->part->flag & PART_CHILD_EFFECT) == 0) {
float effector = 1.0f;
if (vg_effector)
- effector *= psys_particle_value_from_verts(psmd->dm_final, psys->part->from, pa, vg_effector);
+ effector *= psys_particle_value_from_verts(psmd->mesh_final, psys->part->from, pa, vg_effector);
sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co);
length = len_v3(vec);
@@ -2723,7 +2590,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if (sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT) == 0) {
for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
/* ca is safe to cast, since only co and vel are used */
- do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments);
+ do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments);
}
/* lattices have to be calculated separately to avoid mixups between effector calculations */
@@ -2771,219 +2638,255 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
if (vg_length)
MEM_freeN(vg_length);
}
-void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
-{
- ParticleCacheKey *ca, **cache = edit->pathcache;
- ParticleEditSettings *pset = &scene->toolsettings->particle;
- PTCacheEditPoint *point = NULL;
- PTCacheEditKey *ekey = NULL;
-
- ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleData *pa = psys ? psys->particles : NULL;
-
- ParticleInterpolationData pind;
- ParticleKey result;
-
- float birthtime = 0.0f, dietime = 0.0f;
- float t, time = 0.0f, keytime = 0.0f /*, frs_sec */;
- float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
- int k, i;
- int segments = 1 << pset->draw_step;
- int totpart = edit->totpoint, recalc_set = 0;
+typedef struct CacheEditrPathsIterData {
+ Object *object;
+ PTCacheEdit *edit;
+ ParticleSystemModifierData *psmd;
+ ParticleData *pa;
+ int segments;
+ bool use_weight;
float sel_col[3];
float nosel_col[3];
+} CacheEditrPathsIterData;
- segments = MAX2(segments, 4);
-
- if (!cache || edit->totpoint != edit->totcached) {
- /* clear out old and create new empty path cache */
- psys_free_path_cache(edit->psys, edit);
- cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
-
- /* set flag for update (child particles check this too) */
- for (i = 0, point = edit->points; i < totpart; i++, point++)
- point->flag |= PEP_EDIT_RECALC;
- recalc_set = 1;
+static void psys_cache_edit_paths_iter(
+ void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ CacheEditrPathsIterData *iter_data = (CacheEditrPathsIterData *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if (edit->totcached && !(point->flag & PEP_EDIT_RECALC)) {
+ return;
+ }
+ if (point->totkey == 0) {
+ return;
}
+ Object *ob = iter_data->object;
+ ParticleSystem *psys = edit->psys;
+ ParticleCacheKey **cache = edit->pathcache;
+ ParticleSystemModifierData *psmd = iter_data->psmd;
+ ParticleData *pa = iter_data->pa ? iter_data->pa + iter : NULL;
+ PTCacheEditKey *ekey = point->keys;
+ const int segments = iter_data->segments;
+ const bool use_weight = iter_data->use_weight;
- /* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */
+ float birthtime = 0.0f, dietime = 0.0f;
+ float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
- const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
+ ParticleInterpolationData pind;
+ pind.keyed = 0;
+ pind.cache = NULL;
+ pind.epoint = point;
+ pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0;
+ pind.mesh = NULL;
+ /* should init_particle_interpolation set this ? */
if (use_weight) {
- ; /* use weight painting colors now... */
- }
- else {
- sel_col[0] = (float)edit->sel_col[0] / 255.0f;
- sel_col[1] = (float)edit->sel_col[1] / 255.0f;
- sel_col[2] = (float)edit->sel_col[2] / 255.0f;
- nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
- nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
- nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
+ pind.hkey[0] = NULL;
+ /* pa != NULL since the weight brush is only available for hair */
+ pind.hkey[0] = pa->hair;
+ pind.hkey[1] = pa->hair + 1;
}
- /*---first main loop: create all actual particles' paths---*/
- for (i = 0, point = edit->points; i < totpart; i++, pa += pa ? 1 : 0, point++) {
- if (edit->totcached && !(point->flag & PEP_EDIT_RECALC))
- continue;
+ memset(cache[iter], 0, sizeof(*cache[iter]) * (segments + 1));
- if (point->totkey == 0)
- continue;
+ cache[iter]->segments = segments;
- ekey = point->keys;
+ /*--get the first data points--*/
+ init_particle_interpolation(ob, psys, pa, &pind);
- pind.keyed = 0;
- pind.cache = NULL;
- pind.epoint = point;
- pind.bspline = psys ? (psys->part->flag & PART_HAIR_BSPLINE) : 0;
- pind.dm = NULL;
+ if (psys) {
+ psys_mat_hair_to_global(ob, psmd->mesh_final, psys->part->from, pa, hairmat);
+ copy_v3_v3(rotmat[0], hairmat[2]);
+ copy_v3_v3(rotmat[1], hairmat[1]);
+ copy_v3_v3(rotmat[2], hairmat[0]);
+ }
+ birthtime = pind.birthtime;
+ dietime = pind.dietime;
- /* should init_particle_interpolation set this ? */
- if (use_weight) {
- pind.hkey[0] = NULL;
- /* pa != NULL since the weight brush is only available for hair */
- pind.hkey[0] = pa->hair;
- pind.hkey[1] = pa->hair + 1;
- }
+ if (birthtime >= dietime) {
+ cache[iter]->segments = -1;
+ return;
+ }
+ /*--interpolate actual path from data points--*/
+ ParticleCacheKey *ca;
+ int k;
+ float t, time = 0.0f, keytime = 0.0f;
+ for (k = 0, ca = cache[iter]; k <= segments; k++, ca++) {
+ time = (float)k / (float)segments;
+ t = birthtime + time * (dietime - birthtime);
+ ParticleKey result;
+ result.time = -t;
+ do_particle_interpolation(psys, iter, pa, t, &pind, &result);
+ copy_v3_v3(ca->co, result.co);
+
+ /* non-hair points are already in global space */
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ mul_m4_v3(hairmat, ca->co);
- memset(cache[i], 0, sizeof(*cache[i]) * (segments + 1));
+ if (k) {
+ cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
- cache[i]->segments = segments;
+ if (k == segments)
+ copy_qt_qt(ca->rot, (ca - 1)->rot);
- /*--get the first data points--*/
- init_particle_interpolation(ob, psys, pa, &pind);
+ /* set velocity */
+ sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
- if (psys) {
- psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
- copy_v3_v3(rotmat[0], hairmat[2]);
- copy_v3_v3(rotmat[1], hairmat[1]);
- copy_v3_v3(rotmat[2], hairmat[0]);
+ if (k == 1)
+ copy_v3_v3((ca - 1)->vel, ca->vel);
+ }
}
-
- birthtime = pind.birthtime;
- dietime = pind.dietime;
-
- if (birthtime >= dietime) {
- cache[i]->segments = -1;
- continue;
+ else {
+ ca->vel[0] = ca->vel[1] = 0.0f;
+ ca->vel[2] = 1.0f;
}
- /*--interpolate actual path from data points--*/
- for (k = 0, ca = cache[i]; k <= segments; k++, ca++) {
- time = (float)k / (float)segments;
- t = birthtime + time * (dietime - birthtime);
- result.time = -t;
- do_particle_interpolation(psys, i, pa, t, &pind, &result);
- copy_v3_v3(ca->co, result.co);
-
- /* non-hair points are already in global space */
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- mul_m4_v3(hairmat, ca->co);
-
- if (k) {
- cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
-
- if (k == segments)
- copy_qt_qt(ca->rot, (ca - 1)->rot);
-
- /* set velocity */
- sub_v3_v3v3(ca->vel, ca->co, (ca - 1)->co);
-
- if (k == 1)
- copy_v3_v3((ca - 1)->vel, ca->vel);
- }
+ /* selection coloring in edit mode */
+ if (use_weight) {
+ if (k == 0) {
+ BKE_defvert_weight_to_rgb(ca->col, pind.hkey[1]->weight);
}
else {
- ca->vel[0] = ca->vel[1] = 0.0f;
- ca->vel[2] = 1.0f;
- }
-
- /* selection coloring in edit mode */
- if (use_weight) {
- if (k == 0) {
- weight_to_rgb(ca->col, pind.hkey[1]->weight);
+ /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
+ float real_t;
+ if (result.time < 0.0f) {
+ real_t = -result.time;
}
else {
- /* warning: copied from 'do_particle_interpolation' (without 'mvert' array stepping) */
- float real_t;
- if (result.time < 0.0f) {
- real_t = -result.time;
- }
- else {
- real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time);
- }
+ real_t = pind.hkey[0]->time + t * (pind.hkey[0][pa->totkey - 1].time - pind.hkey[0]->time);
+ }
- while (pind.hkey[1]->time < real_t) {
- pind.hkey[1]++;
- }
- pind.hkey[0] = pind.hkey[1] - 1;
- /* end copy */
+ while (pind.hkey[1]->time < real_t) {
+ pind.hkey[1]++;
+ }
+ pind.hkey[0] = pind.hkey[1] - 1;
+ /* end copy */
- float w1[3], w2[3];
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ float w1[3], w2[3];
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- weight_to_rgb(w1, pind.hkey[0]->weight);
- weight_to_rgb(w2, pind.hkey[1]->weight);
+ BKE_defvert_weight_to_rgb(w1, pind.hkey[0]->weight);
+ BKE_defvert_weight_to_rgb(w2, pind.hkey[1]->weight);
- interp_v3_v3v3(ca->col, w1, w2, keytime);
+ interp_v3_v3v3(ca->col, w1, w2, keytime);
+ }
+ }
+ else {
+ if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
+ if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
+ copy_v3_v3(ca->col, iter_data->sel_col);
+ }
+ else {
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ interp_v3_v3v3(ca->col, iter_data->sel_col, iter_data->nosel_col, keytime);
}
}
else {
- if ((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT) {
- if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
- copy_v3_v3(ca->col, sel_col);
- }
- else {
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, sel_col, nosel_col, keytime);
- }
+ if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
+ keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
+ interp_v3_v3v3(ca->col, iter_data->nosel_col, iter_data->sel_col, keytime);
}
else {
- if ((ekey + (pind.ekey[1] - point->keys))->flag & PEK_SELECT) {
- keytime = (t - (*pind.ekey[0]->time)) / ((*pind.ekey[1]->time) - (*pind.ekey[0]->time));
- interp_v3_v3v3(ca->col, nosel_col, sel_col, keytime);
- }
- else {
- copy_v3_v3(ca->col, nosel_col);
- }
+ copy_v3_v3(ca->col, iter_data->nosel_col);
}
}
-
- ca->time = t;
}
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- /* First rotation is based on emitting face orientation.
- * This is way better than having flipping rotations resulting
- * from using a global axis as a rotation pole (vec_to_quat()).
- * It's not an ideal solution though since it disregards the
- * initial tangent, but taking that in to account will allow
- * the possibility of flipping again. -jahka
- */
- mat3_to_quat_is_ok(cache[i]->rot, rotmat);
+
+ ca->time = t;
+ }
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ /* First rotation is based on emitting face orientation.
+ * This is way better than having flipping rotations resulting
+ * from using a global axis as a rotation pole (vec_to_quat()).
+ * It's not an ideal solution though since it disregards the
+ * initial tangent, but taking that in to account will allow
+ * the possibility of flipping again. -jahka
+ */
+ mat3_to_quat_is_ok(cache[iter]->rot, rotmat);
+ }
+}
+
+void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
+{
+ ParticleCacheKey **cache = edit->pathcache;
+ ParticleEditSettings *pset = &scene->toolsettings->particle;
+
+ ParticleSystem *psys = edit->psys;
+
+ ParticleData *pa = psys ? psys->particles : NULL;
+
+ int segments = 1 << pset->draw_step;
+ int totpart = edit->totpoint, recalc_set = 0;
+
+ segments = MAX2(segments, 4);
+
+ if (!cache || edit->totpoint != edit->totcached) {
+ /* Clear out old and create new empty path cache. */
+ psys_free_path_cache(edit->psys, edit);
+ cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
+ /* Set flag for update (child particles check this too). */
+ int i;
+ PTCacheEditPoint *point;
+ for (i = 0, point = edit->points; i < totpart; i++, point++) {
+ point->flag |= PEP_EDIT_RECALC;
}
+ recalc_set = 1;
+ }
+
+ const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
+
+ CacheEditrPathsIterData iter_data;
+ iter_data.object = ob;
+ iter_data.edit = edit;
+ iter_data.psmd = edit->psmd_eval;
+ iter_data.pa = pa;
+ iter_data.segments = segments;
+ iter_data.use_weight = use_weight;
+
+ if (use_weight) {
+ ; /* use weight painting colors now... */
+ }
+ else {
+ iter_data.sel_col[0] = (float)edit->sel_col[0] / 255.0f;
+ iter_data.sel_col[1] = (float)edit->sel_col[1] / 255.0f;
+ iter_data.sel_col[2] = (float)edit->sel_col[2] / 255.0f;
+ iter_data.nosel_col[0] = (float)edit->nosel_col[0] / 255.0f;
+ iter_data.nosel_col[1] = (float)edit->nosel_col[1] / 255.0f;
+ iter_data.nosel_col[2] = (float)edit->nosel_col[2] / 255.0f;
}
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, psys_cache_edit_paths_iter, &settings);
+
edit->totcached = totpart;
if (psys) {
ParticleSimulationData sim = {0};
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
- sim.psmd = psys_get_modifier(ob, psys);
+ sim.psmd = edit->psmd_eval;
psys_cache_child_paths(&sim, cfra, true, use_render_params);
}
/* clear recalc flag if set here */
if (recalc_set) {
- for (i = 0, point = edit->points; i < totpart; i++, point++)
+ PTCacheEditPoint *point;
+ int i;
+ for (i = 0, point = edit->points; i < totpart; i++, point++) {
point->flag &= ~PEP_EDIT_RECALC;
+ }
}
}
/************************************************/
@@ -3007,22 +2910,6 @@ void psys_get_from_key(ParticleKey *key, float loc[3], float vel[3], float rot[4
if (rot) copy_qt_qt(rot, key->rot);
if (time) *time = key->time;
}
-/*-------changing particle keys from space to another-------*/
-#if 0
-static void key_from_object(Object *ob, ParticleKey *key)
-{
- float q[4];
-
- add_v3_v3(key->vel, key->co);
-
- mul_m4_v3(ob->obmat, key->co);
- mul_m4_v3(ob->obmat, key->vel);
- mat4_to_quat(q, ob->obmat);
-
- sub_v3_v3v3(key->vel, key->vel, key->co);
- mul_qt_qtqt(key->rot, q, key->rot);
-}
-#endif
static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat[4][4])
{
@@ -3065,7 +2952,7 @@ static void triatomat(float *v1, float *v2, float *v3, float (*uv)[2], float mat
cross_v3_v3v3(mat[0], mat[1], mat[2]);
}
-static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float mat[4][4], int orco)
+static void psys_face_mat(Object *ob, Mesh *mesh, ParticleData *pa, float mat[4][4], int orco)
{
float v[3][3];
MFace *mface;
@@ -3073,72 +2960,72 @@ static void psys_face_mat(Object *ob, DerivedMesh *dm, ParticleData *pa, float m
float (*orcodata)[3];
int i = (ELEM(pa->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? pa->num : pa->num_dmcache;
- if (i == -1 || i >= dm->getNumTessFaces(dm)) { unit_m4(mat); return; }
+ if (i == -1 || i >= mesh->totface) { unit_m4(mat); return; }
- mface = dm->getTessFaceData(dm, i, CD_MFACE);
- osface = dm->getTessFaceData(dm, i, CD_ORIGSPACE);
+ mface = &mesh->mface[i];
+ osface = CustomData_get(&mesh->fdata, i, CD_ORIGSPACE);
- if (orco && (orcodata = dm->getVertDataArray(dm, CD_ORCO))) {
+ if (orco && (orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO))) {
copy_v3_v3(v[0], orcodata[mface->v1]);
copy_v3_v3(v[1], orcodata[mface->v2]);
copy_v3_v3(v[2], orcodata[mface->v3]);
/* ugly hack to use non-transformed orcos, since only those
* give symmetric results for mirroring in particle mode */
- if (DM_get_vert_data_layer(dm, CD_ORIGINDEX))
+ if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
BKE_mesh_orco_verts_transform(ob->data, v, 3, 1);
}
else {
- dm->getVertCo(dm, mface->v1, v[0]);
- dm->getVertCo(dm, mface->v2, v[1]);
- dm->getVertCo(dm, mface->v3, v[2]);
+ copy_v3_v3(v[0], mesh->mvert[mface->v1].co);
+ copy_v3_v3(v[1], mesh->mvert[mface->v2].co);
+ copy_v3_v3(v[2], mesh->mvert[mface->v3].co);
}
triatomat(v[0], v[1], v[2], (osface) ? osface->uv : NULL, mat);
}
-void psys_mat_hair_to_object(Object *UNUSED(ob), DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_object(Object *UNUSED(ob), Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
float vec[3];
/* can happen when called from a different object's modifier */
- if (!dm) {
+ if (!mesh) {
unit_m4(hairmat);
return;
}
- psys_face_mat(0, dm, pa, hairmat, 0);
- psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0, 0);
+ psys_face_mat(0, mesh, pa, hairmat, 0);
+ psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, 0);
copy_v3_v3(hairmat[3], vec);
}
-void psys_mat_hair_to_orco(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_orco(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
float vec[3], orco[3];
- psys_face_mat(ob, dm, pa, hairmat, 1);
- psys_particle_on_dm(dm, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco, 0);
+ psys_face_mat(ob, mesh, pa, hairmat, 1);
+ psys_particle_on_dm(mesh, from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, vec, 0, 0, 0, orco);
/* see psys_face_mat for why this function is called */
- if (DM_get_vert_data_layer(dm, CD_ORIGINDEX))
+ if (CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX))
BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1);
copy_v3_v3(hairmat[3], orco);
}
-void psys_vec_rot_to_face(DerivedMesh *dm, ParticleData *pa, float vec[3])
+void psys_vec_rot_to_face(Mesh *mesh, ParticleData *pa, float vec[3])
{
float mat[4][4];
- psys_face_mat(0, dm, pa, mat, 0);
+ psys_face_mat(0, mesh, pa, mat, 0);
transpose_m4(mat); /* cheap inverse for rotation matrix */
mul_mat3_m4_v3(mat, vec);
}
-void psys_mat_hair_to_global(Object *ob, DerivedMesh *dm, short from, ParticleData *pa, float hairmat[4][4])
+void psys_mat_hair_to_global(Object *ob, Mesh *mesh, short from, ParticleData *pa, float hairmat[4][4])
{
float facemat[4][4];
- psys_mat_hair_to_object(ob, dm, from, pa, facemat);
+ psys_mat_hair_to_object(ob, mesh, from, pa, facemat);
mul_m4_m4m4(hairmat, ob->obmat, facemat);
}
@@ -3186,8 +3073,8 @@ ModifierData *object_add_particle_system(Main *bmain, Scene *scene, Object *ob,
psys->flag = PSYS_CURRENT;
psys->cfra = BKE_scene_frame_get_from_ctime(scene, CFRA + 1);
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
return md;
}
@@ -3232,8 +3119,11 @@ void object_remove_particle_system(Main *bmain, Scene *UNUSED(scene), Object *ob
else
ob->mode &= ~OB_MODE_PARTICLE_EDIT;
- DAG_relations_tag_update(bmain);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ DEG_relations_tag_update(bmain);
+ DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
}
static void default_particle_settings(ParticleSettings *part)
@@ -3296,7 +3186,7 @@ static void default_particle_settings(ParticleSettings *part)
part->clength = 1.0f;
part->clength_thres = 0.0f;
- part->draw = PART_DRAW_EMITTER;
+ part->draw = 0;
part->draw_line[0] = 0.5;
part->path_start = 0.0f;
part->path_end = 1.0f;
@@ -3308,16 +3198,18 @@ static void default_particle_settings(ParticleSettings *part)
part->color_vec_max = 1.f;
part->draw_col = PART_DRAW_COL_MAT;
- part->simplify_refsize = 1920;
- part->simplify_rate = 1.0f;
- part->simplify_transition = 0.1f;
- part->simplify_viewport = 0.8;
-
if (!part->effector_weights)
part->effector_weights = BKE_add_effector_weights(NULL);
part->omat = 1;
part->use_modifier_stack = false;
+ part->draw_size = 0.1f;
+
+ part->shape_flag = PART_SHAPE_CLOSE_TIP;
+ part->shape = 0.0f;
+ part->rad_root = 1.0f;
+ part->rad_tip = 0.0f;
+ part->rad_scale = 0.01f;
}
@@ -3421,25 +3313,25 @@ void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const
/* Textures */
/************************************************/
-static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const float fuv[4],
+static int get_particle_uv(Mesh *mesh, ParticleData *pa, int index, const float fuv[4],
char *name, float *texco, bool from_vert)
{
MFace *mf;
MTFace *tf;
int i;
- tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, name);
+ tf = CustomData_get_layer_named(&mesh->fdata, CD_MTFACE, name);
if (tf == NULL)
- tf = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+ tf = mesh->mtface;
if (tf == NULL)
return 0;
if (pa) {
i = ELEM(pa->num_dmcache, DMCACHE_NOTFOUND, DMCACHE_ISCHILD) ? pa->num : pa->num_dmcache;
- if ((!from_vert && i >= dm->getNumTessFaces(dm)) ||
- (from_vert && i >= dm->getNumVerts(dm)))
+ if ((!from_vert && i >= mesh->totface) ||
+ (from_vert && i >= mesh->totvert))
{
i = -1;
}
@@ -3455,12 +3347,12 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f
}
else {
if (from_vert) {
- mf = dm->getTessFaceDataArray(dm, CD_MFACE);
+ mf = mesh->mface;
/* This finds the first face to contain the emitting vertex,
* this is not ideal, but is mostly fine as UV seams generally
* map to equal-colored parts of a texture */
- for (int j = 0; j < dm->getNumTessFaces(dm); j++, mf++) {
+ for (int j = 0; j < mesh->totface; j++, mf++) {
if (ELEM(i, mf->v1, mf->v2, mf->v3, mf->v4)) {
i = j;
break;
@@ -3468,7 +3360,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f
}
}
else {
- mf = dm->getTessFaceData(dm, i, CD_MFACE);
+ mf = &mesh->mface[i];
}
psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
@@ -3503,7 +3395,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int index, const f
CLAMP(pvalue, -1.0f, 1.0f); \
} (void)0
-static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra)
+static void get_cpa_texture(Mesh *mesh, ParticleSystem *psys, ParticleSettings *part, ParticleData *par, int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra)
{
MTex *mtex, **mtexp = part->mtex;
int m;
@@ -3537,7 +3429,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (fw && get_particle_uv(dm, NULL, face_index, fw, mtex->uvname,
+ if (fw && get_particle_uv(mesh, NULL, face_index, fw, mtex->uvname,
texvec, (part->from == PART_FROM_VERT)))
{
break;
@@ -3615,7 +3507,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (get_particle_uv(sim->psmd->dm_final, pa, 0, pa->fuv, mtex->uvname,
+ if (get_particle_uv(sim->psmd->mesh_final, pa, 0, pa->fuv, mtex->uvname,
texvec, (part->from == PART_FROM_VERT)))
{
break;
@@ -3623,7 +3515,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
/* no break, failed to get uv's, so let's try orco's */
ATTR_FALLTHROUGH;
case TEXCO_ORCO:
- psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec, 0);
+ psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec);
if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
BKE_mesh_texspace_calc(me);
@@ -3745,28 +3637,28 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
ParticleSystem *psys = ctx->sim.psys;
int i = cpa - psys->child;
- get_cpa_texture(ctx->dm, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+ get_cpa_texture(ctx->mesh, psys, part, psys->particles + cpa->pa[0], i, cpa_num, cpa_fuv, orco, ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
if (ptex->exist < psys_frand(psys, i + 24))
return;
if (ctx->vg_length)
- ptex->length *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_length);
+ ptex->length *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_length);
if (ctx->vg_clump)
- ptex->clump *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump);
+ ptex->clump *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump);
if (ctx->vg_kink)
- ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
+ ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
if (ctx->vg_rough1)
- ptex->rough1 *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1);
+ ptex->rough1 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1);
if (ctx->vg_rough2)
- ptex->rough2 *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2);
+ ptex->rough2 *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough2);
if (ctx->vg_roughe)
- ptex->roughe *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe);
+ ptex->roughe *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_roughe);
if (ctx->vg_effector)
- ptex->effector *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
+ ptex->effector *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
if (ctx->vg_twist)
- ptex->twist *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
+ ptex->twist *= psys_interpolate_value_from_verts(ctx->mesh, cpa_from, cpa_num, cpa_fuv, ctx->vg_twist);
}
/* get's hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, const bool vel)
@@ -3819,22 +3711,22 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
/* pind.dm disabled in editmode means we don't get effectors taken into
* account when subdividing for instance */
- pind.dm = psys_in_edit_mode(sim->scene, psys) ? NULL : psys->hair_out_dm;
+ pind.mesh = psys_in_edit_mode(sim->depsgraph, psys) ? NULL : psys->hair_out_mesh; /* XXX Sybren EEK */
init_particle_interpolation(sim->ob, psys, pa, &pind);
do_particle_interpolation(psys, p, pa, t, &pind, state);
- if (pind.dm) {
+ if (pind.mesh) {
mul_m4_v3(sim->ob->obmat, state->co);
mul_mat3_m4_v3(sim->ob->obmat, state->vel);
}
else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) {
if ((pa->flag & PARS_REKEY) == 0) {
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, part->from, pa, hairmat);
mul_m4_v3(hairmat, state->co);
mul_mat3_m4_v3(hairmat, state->vel);
if (sim->psys->effectors && (part->flag & PART_CHILD_GUIDE) == 0) {
- do_guides(sim->psys->part, sim->psys->effectors, state, p, state->time);
+ do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, state, p, state->time);
/* TODO: proper velocity handling */
}
@@ -3885,7 +3777,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
cpa_fuv = cpa->fuv;
cpa_from = PART_FROM_FACE;
- psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa->fuv, foffset, co, 0, 0, 0, orco);
/* we need to save the actual root position of the child for positioning it accurately to the surface of the emitter */
//copy_v3_v3(cpa_1st, co);
@@ -3894,9 +3786,9 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
pa = psys->particles + cpa->parent;
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco);
if (part->type == PART_HAIR)
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
else
unit_m4(hairmat);
@@ -3914,10 +3806,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
cpa_num = pa->num;
cpa_fuv = pa->fuv;
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco);
if (part->type == PART_HAIR) {
- psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco, 0);
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
}
else {
copy_v3_v3(orco, cpa->fuv);
@@ -3925,18 +3817,10 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
}
}
- /* correct child ipo timing */
-#if 0 // XXX old animation system
- if ((part->flag & PART_ABS_TIME) == 0 && part->ipo) {
- calc_ipo(part->ipo, 100.0f * t);
- execute_ipo((ID *)part, part->ipo);
- }
-#endif // XXX old animation system
-
/* get different child parameters from textures & vgroups */
memset(&ctx, 0, sizeof(ParticleThreadContext));
ctx.sim = *sim;
- ctx.dm = psmd->dm_final;
+ ctx.mesh = psmd->mesh_final;
ctx.ma = ma;
/* TODO: assign vertex groups */
get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
@@ -4020,7 +3904,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
float timestep = psys_get_timestep(sim);
/* negative time means "use current time" */
- cfra = state->time > 0 ? state->time : BKE_scene_frame_get(sim->scene);
+ cfra = state->time > 0 ? state->time : DEG_get_ctime(sim->depsgraph);
if (p >= totpart) {
if (!psys->totchild)
@@ -4190,18 +4074,18 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
bool is_grid = (part->distr == PART_DISTR_GRID && part->from != PART_FROM_VERT);
if (cpa) {
- if ((part->childtype == PART_CHILD_FACES) && (psmd->dm_final != NULL)) {
- CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
+ if ((part->childtype == PART_CHILD_FACES) && (psmd->mesh_final != NULL)) {
+ CustomData *mtf_data = &psmd->mesh_final->fdata;
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
if (mtface && !is_grid) {
- mface = psmd->dm_final->getTessFaceData(psmd->dm_final, cpa->num, CD_MFACE);
+ mface = CustomData_get(&psmd->mesh_final->fdata, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
}
- psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, 0, 0, 0, orco);
return;
}
else {
@@ -4209,8 +4093,8 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
}
}
- if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL) && !is_grid) {
- CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
+ if ((part->from == PART_FROM_FACE) && (psmd->mesh_final != NULL) && !is_grid) {
+ CustomData *mtf_data = &psmd->mesh_final->fdata;
const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
@@ -4219,20 +4103,20 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
if (num == DMCACHE_NOTFOUND)
num = pa->num;
- if (num >= psmd->dm_final->getNumTessFaces(psmd->dm_final)) {
+ if (num >= psmd->mesh_final->totface) {
/* happens when simplify is enabled
* gives invalid coords but would crash otherwise */
num = DMCACHE_NOTFOUND;
}
if (mtface && !ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
+ mface = CustomData_get(&psmd->mesh_final->fdata, num, CD_MFACE);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
}
}
- psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco, 0);
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, 0, 0, 0, orco);
}
void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[4][4], float *scale)
@@ -4250,9 +4134,9 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa
pa = psys->particles + cpa->pa[0];
if (pa)
- psys_particle_on_emitter(psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0, 0);
+ psys_particle_on_emitter(psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, loc, nor, 0, 0, 0);
else
- psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, nor, 0, 0, 0, 0);
+ psys_particle_on_emitter(psmd, PART_FROM_FACE, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, loc, nor, 0, 0, 0);
if (psys->part->rotmode == PART_ROT_VEL) {
transpose_m3_m4(nmat, ob->imat);
@@ -4384,9 +4268,10 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
madd_v3_v3fl(center, yvec, bb->offset[1]);
}
-void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
+void psys_apply_hair_lattice(Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys)
{
ParticleSimulationData sim = {0};
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
@@ -4401,7 +4286,7 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
float hairmat[4][4], imat[4][4];
for (p = 0; p < psys->totpart; p++, pa++) {
- psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim.ob, sim.psmd->mesh_final, psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
hkey = pa->hair;
@@ -4419,3 +4304,22 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
psys->flag |= PSYS_EDITED;
}
}
+
+
+
+/* Draw Engine */
+void (*BKE_particle_batch_cache_dirty_tag_cb)(ParticleSystem *psys, int mode) = NULL;
+void (*BKE_particle_batch_cache_free_cb)(ParticleSystem *psys) = NULL;
+
+void BKE_particle_batch_cache_dirty_tag(ParticleSystem *psys, int mode)
+{
+ if (psys->batch_cache) {
+ BKE_particle_batch_cache_dirty_tag_cb(psys, mode);
+ }
+}
+void BKE_particle_batch_cache_free(ParticleSystem *psys)
+{
+ if (psys->batch_cache) {
+ BKE_particle_batch_cache_free_cb(psys);
+ }
+}
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 79c3f247232..0cba5f5a2fc 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -39,40 +39,6 @@
#include "particle_private.h"
-struct Material;
-
-static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3])
-{
- float cross[3], nstrand[3], vnor[3], blend;
-
- if (!((ma->mode & MA_STR_SURFDIFF) || (ma->strand_surfnor > 0.0f)))
- return;
-
- if (ma->mode & MA_STR_SURFDIFF) {
- cross_v3_v3v3(cross, surfnor, nor);
- cross_v3_v3v3(nstrand, nor, cross);
-
- blend = dot_v3v3(nstrand, surfnor);
- CLAMP(blend, 0.0f, 1.0f);
-
- interp_v3_v3v3(vnor, nstrand, surfnor, blend);
- normalize_v3(vnor);
- }
- else {
- copy_v3_v3(vnor, nor);
- }
-
- if (ma->strand_surfnor > 0.0f) {
- if (ma->strand_surfnor > surfdist) {
- blend = (ma->strand_surfnor - surfdist) / ma->strand_surfnor;
- interp_v3_v3v3(vnor, vnor, surfnor, blend);
- normalize_v3(vnor);
- }
- }
-
- copy_v3_v3(nor, vnor);
-}
-
/* ------------------------------------------------------------------------- */
typedef struct ParticlePathIterator {
@@ -320,7 +286,7 @@ static bool check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *k
}
void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *modifiers,
- ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
+ ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], float hairmat[4][4],
ParticleCacheKey *keys, ParticleCacheKey *parent_keys, const float parent_orco[3])
{
struct ParticleSettings *part = ctx->sim.psys->part;
@@ -333,11 +299,8 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
int totkeys, k;
float max_length;
-#if 0 /* TODO for the future: use true particle modifiers that work on the whole curve */
- for (mod = modifiers->first; mod; mod = mod->next) {
- mod->apply(keys, totkeys, parent_keys);
- }
-#else
+ /* TODO for the future: use true particle modifiers that work on the whole curve */
+
(void)modifiers;
(void)mod;
@@ -389,9 +352,6 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
if (k >= 2) {
sub_v3_v3v3((key-1)->vel, key->co, (key-2)->co);
mul_v3_fl((key-1)->vel, 0.5);
-
- if (ma && draw_col_ma)
- get_strand_normal(ma, ornor, cur_length, (key-1)->vel);
}
if (use_length_check && k > 0) {
@@ -413,11 +373,9 @@ void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *mod
if (ma && draw_col_ma) {
copy_v3_v3(key->col, &ma->r);
- get_strand_normal(ma, ornor, cur_length, key->vel);
}
}
}
-#endif
}
/* ------------------------------------------------------------------------- */
@@ -820,7 +778,7 @@ void do_child_modifiers(const ParticleChildModifierContext *modifier_ctx,
if (part->flag & PART_CHILD_EFFECT)
/* state is safe to cast, since only co and vel are used */
- guided = do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
+ guided = do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
if (guided == 0) {
float orco_offset[3];
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 8a3b1312590..6c5a9085e71 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -50,14 +50,13 @@
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
-static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot);
+#include "DEG_depsgraph_query.h"
static void alloc_child_particles(ParticleSystem *psys, int tot)
{
@@ -80,12 +79,13 @@ static void alloc_child_particles(ParticleSystem *psys, int tot)
}
}
-static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, DerivedMesh *deformdm, ParticleSystem *psys)
+static void distribute_simple_children(Scene *scene, Object *ob, Mesh *final_mesh, Mesh *deform_mesh, ParticleSystem *psys, const bool use_render_params)
{
ChildParticle *cpa = NULL;
int i, p;
- int child_nbr= psys_get_child_number(scene, psys);
- int totpart= psys_get_tot_child(scene, psys);
+ int child_nbr= psys_get_child_number(scene, psys, use_render_params);
+ int totpart= psys_get_tot_child(scene, psys, use_render_params);
+ RNG *rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
alloc_child_particles(psys, totpart);
@@ -97,9 +97,9 @@ static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *fi
/* create even spherical distribution inside unit sphere */
while (length>=1.0f) {
- cpa->fuv[0]=2.0f*BLI_frand()-1.0f;
- cpa->fuv[1]=2.0f*BLI_frand()-1.0f;
- cpa->fuv[2]=2.0f*BLI_frand()-1.0f;
+ cpa->fuv[0]=2.0f*BLI_rng_get_float(rng)-1.0f;
+ cpa->fuv[1]=2.0f*BLI_rng_get_float(rng)-1.0f;
+ cpa->fuv[2]=2.0f*BLI_rng_get_float(rng)-1.0f;
length=len_v3(cpa->fuv);
}
@@ -107,14 +107,16 @@ static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *fi
}
}
/* dmcache must be updated for parent particles if children from faces is used */
- psys_calc_dmcache(ob, finaldm, deformdm, psys);
+ psys_calc_dmcache(ob, final_mesh, deform_mesh, psys);
+
+ BLI_rng_free(rng);
}
-static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
+static void distribute_grid(Mesh *mesh, ParticleSystem *psys)
{
ParticleData *pa=NULL;
float min[3], max[3], delta[3], d;
- MVert *mv, *mvert = dm->getVertDataArray(dm,0);
- int totvert=dm->getNumVerts(dm), from=psys->part->from;
+ MVert *mv, *mvert = mesh->mvert;
+ int totvert=mesh->totvert, from=psys->part->from;
int i, j, k, p, res=psys->part->grid_res, size[3], axis;
/* find bounding box of dm */
@@ -196,8 +198,8 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
int a, a1, a2, a0mul, a1mul, a2mul, totface;
int amax= from==PART_FROM_FACE ? 3 : 1;
- totface=dm->getNumTessFaces(dm);
- mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);
+ totface = mesh->totface;
+ mface = mface_array = mesh->mface;
for (a=0; a<amax; a++) {
if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; }
@@ -314,19 +316,16 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
static void hammersley_create(float *out, int n, int seed, float amount)
{
RNG *rng;
- double p, t, offs[2];
- int k, kk;
+
+ double offs[2], t;
rng = BLI_rng_new(31415926 + n + seed);
offs[0] = BLI_rng_get_double(rng) + (double)amount;
offs[1] = BLI_rng_get_double(rng) + (double)amount;
BLI_rng_free(rng);
- for (k = 0; k < n; k++) {
- t = 0;
- for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1)
- if (kk & 1) /* kk mod 2 = 1 */
- t += p;
+ for (int k = 0; k < n; k++) {
+ BLI_hammersley_1D(k, &t);
out[2*k + 0] = fmod((double)k/(double)n + offs[0], 1.0);
out[2*k + 1] = fmod(t + offs[1], 1.0);
@@ -434,7 +433,7 @@ static int distribute_binary_search(float *sum, int n, float value)
/* the max number if calls to rng_* funcs within psys_thread_distribute_particle
* be sure to keep up to date if this changes */
-#define PSYS_RND_DIST_SKIP 2
+#define PSYS_RND_DIST_SKIP 3
/* note: this function must be thread safe, for from == PART_FROM_CHILD */
#define ONLY_WORKING_WITH_PA_VERTS 0
@@ -443,7 +442,7 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
ParticleThreadContext *ctx= thread->ctx;
MFace *mface;
- mface = ctx->dm->getTessFaceDataArray(ctx->dm, CD_MFACE);
+ mface = ctx->mesh->mface;
int rng_skip_tot = PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
@@ -452,12 +451,12 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
zero_v4(pa->fuv);
- if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->dm->getNumVerts(ctx->dm)) {
+ if (pa->num != DMCACHE_NOTFOUND && pa->num < ctx->mesh->totvert) {
/* This finds the first face to contain the emitting vertex,
* this is not ideal, but is mostly fine as UV seams generally
* map to equal-colored parts of a texture */
- for (int i = 0; i < ctx->dm->getNumTessFaces(ctx->dm); i++, mface++) {
+ for (int i = 0; i < ctx->mesh->totface; i++, mface++) {
if (ELEM(pa->num, mface->v1, mface->v2, mface->v3, mface->v4)) {
unsigned int *vert = &mface->v1;
@@ -478,8 +477,8 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
KDTreeNearest ptn[3];
int w, maxw;
- psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
+ psys_particle_on_dm(ctx->mesh,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
+ BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1);
maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
for (w=0; w<maxw; w++) {
@@ -488,13 +487,15 @@ static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, i
}
#endif
- if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_assert(rng_skip_tot > 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, int p) {
ParticleThreadContext *ctx= thread->ctx;
- DerivedMesh *dm= ctx->dm;
+ Mesh *mesh = ctx->mesh;
float randu, randv;
int distr= ctx->distr;
int i;
@@ -503,7 +504,7 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
MFace *mface;
pa->num = i = ctx->index[p];
- mface = dm->getTessFaceData(dm,i,CD_MFACE);
+ mface = &mesh->mface[i];
switch (distr) {
case PART_DISTR_JIT:
@@ -530,13 +531,15 @@ static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, i
}
pa->foffset= 0.0f;
- if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_assert(rng_skip_tot > 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
ParticleThreadContext *ctx= thread->ctx;
- DerivedMesh *dm= ctx->dm;
+ Mesh *mesh = ctx->mesh;
float *v1, *v2, *v3, *v4, nor[3], co[3];
float cur_d, min_d, randu, randv;
int distr= ctx->distr;
@@ -544,10 +547,10 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
MFace *mface;
- MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
+ MVert *mvert = mesh->mvert;
pa->num = i = ctx->index[p];
- mface = dm->getTessFaceData(dm,i,CD_MFACE);
+ mface = &mesh->mface[i];
switch (distr) {
case PART_DISTR_JIT:
@@ -575,9 +578,9 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
pa->foffset= 0.0f;
/* experimental */
- tot=dm->getNumTessFaces(dm);
+ tot = mesh->totface;
- psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0,0);
+ psys_interpolate_face(mvert,mface,0,0,pa->fuv,co,nor,0,0,0);
normalize_v3(nor);
negate_v3(nor);
@@ -585,7 +588,7 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
min_d=FLT_MAX;
intersect=0;
- for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
+ for (i=0, mface=mesh->mface; i<tot; i++,mface++) {
if (i==pa->num) continue;
v1=mvert[mface->v1].co;
@@ -619,19 +622,22 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)];
break;
case PART_DISTR_RAND:
- pa->foffset *= BLI_frand();
+ pa->foffset *= BLI_rng_get_float(thread->rng);
+ rng_skip_tot--;
break;
}
}
- if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_assert(rng_skip_tot > 0); /* should never be below zero */
+ if (rng_skip_tot > 0) {
BLI_rng_skip(thread->rng, rng_skip_tot);
+ }
}
static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, int p) {
ParticleThreadContext *ctx= thread->ctx;
Object *ob= ctx->sim.ob;
- DerivedMesh *dm= ctx->dm;
+ Mesh *mesh = ctx->mesh;
float orco1[3], co1[3], nor1[3];
float randu, randv;
int cfrom= ctx->cfrom;
@@ -647,7 +653,7 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
return;
}
- mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);
+ mf = &mesh->mface[ctx->index[p]];
randu= BLI_rng_get_float(thread->rng);
randv= BLI_rng_get_float(thread->rng);
@@ -664,8 +670,8 @@ static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, i
int parent[10];
float pweight[10];
- psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
+ psys_particle_on_dm(mesh,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1);
+ BKE_mesh_orco_verts_transform(ob->data, &orco1, 1, 1);
maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
maxd=ptn[maxw-1].dist;
@@ -743,16 +749,10 @@ static void exec_distribute_child(TaskPool * __restrict UNUSED(pool), void *task
/* RNG skipping at the beginning */
cpa = psys->child;
for (p = 0; p < task->begin; ++p, ++cpa) {
- if (task->ctx->skip) /* simplification skip */
- BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
-
BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP);
}
for (; p < task->end; ++p, ++cpa) {
- if (task->ctx->skip) /* simplification skip */
- BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
-
distribute_children_exec(task, cpa, p);
}
}
@@ -779,11 +779,15 @@ static int distribute_compare_orig_index(const void *p1, const void *p2, void *u
return 1;
}
-static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from)
+static void distribute_invalid(ParticleSimulationData *sim, int from)
{
+ Scene *scene = sim->scene;
+ ParticleSystem *psys = sim->psys;
+ const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
+
if (from == PART_FROM_CHILD) {
ChildParticle *cpa;
- int p, totchild = psys_get_tot_child(scene, psys);
+ int p, totchild = psys_get_tot_child(scene, psys, use_render_params);
if (psys->child && totchild) {
for (p=0,cpa=psys->child; p<totchild; p++,cpa++) {
@@ -805,19 +809,18 @@ static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from)
}
}
-/* Creates a distribution of coordinates on a DerivedMesh */
-/* This is to denote functionality that does not yet work with mesh - only derived mesh */
+/* Creates a distribution of coordinates on a Mesh */
static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, ParticleSimulationData *sim, int from)
{
Scene *scene = sim->scene;
- DerivedMesh *finaldm = sim->psmd->dm_final;
+ Mesh *final_mesh = sim->psmd->mesh_final;
Object *ob = sim->ob;
ParticleSystem *psys= sim->psys;
ParticleData *pa=0, *tpars= 0;
ParticleSettings *part;
ParticleSeam *seams= 0;
KDTree *tree=0;
- DerivedMesh *dm= NULL;
+ Mesh *mesh = NULL;
float *jit= NULL;
int i, p=0;
int cfrom=0;
@@ -825,6 +828,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
int jitlevel= 1, distr;
float *element_weight=NULL,*jitter_offset=NULL, *vweight=NULL;
float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3];
+ RNG *rng = NULL;
if (ELEM(NULL, ob, psys, psys->part))
return 0;
@@ -834,7 +838,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
if (totpart==0)
return 0;
- if (!finaldm->deformedOnly && !finaldm->getTessFaceDataArray(finaldm, CD_ORIGINDEX)) {
+ if (!final_mesh->runtime.deformed_only && !CustomData_get_layer(&final_mesh->fdata, CD_ORIGINDEX)) {
printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
// XXX error("Can't paint with the current modifier stack, disable destructive modifiers");
return 0;
@@ -847,32 +851,37 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
psys_thread_context_init(ctx, sim);
+ const bool use_render_params = (DEG_get_mode(sim->depsgraph) == DAG_EVAL_RENDER);
+
/* First handle special cases */
if (from == PART_FROM_CHILD) {
/* Simple children */
if (part->childtype != PART_CHILD_FACES) {
- BLI_srandom(31415926 + psys->seed + psys->child_seed);
- distribute_simple_children(scene, ob, finaldm, sim->psmd->dm_deformed, psys);
+ distribute_simple_children(scene, ob, final_mesh, sim->psmd->mesh_original, psys, use_render_params);
return 0;
}
}
else {
/* Grid distribution */
if (part->distr==PART_DISTR_GRID && from != PART_FROM_VERT) {
- BLI_srandom(31415926 + psys->seed);
-
if (psys->part->use_modifier_stack) {
- dm = finaldm;
+ mesh = final_mesh;
}
else {
- dm = CDDM_from_mesh((Mesh*)ob->data);
+ BKE_id_copy_ex(
+ NULL, ob->data, (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
}
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
- distribute_grid(dm,psys);
+ distribute_grid(mesh,psys);
- if (dm != finaldm) {
- dm->release(dm);
+ if (mesh != final_mesh) {
+ BKE_id_free(NULL, mesh);
}
return 0;
@@ -881,54 +890,61 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
/* Create trees and original coordinates if needed */
if (from == PART_FROM_CHILD) {
- distr=PART_DISTR_RAND;
- BLI_srandom(31415926 + psys->seed + psys->child_seed);
- dm= finaldm;
+ distr = PART_DISTR_RAND;
+ rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
+ mesh= final_mesh;
/* BMESH ONLY */
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
children=1;
tree=BLI_kdtree_new(totpart);
for (p=0,pa=psys->particles; p<totpart; p++,pa++) {
- psys_particle_on_dm(dm,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco,NULL);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco, 1, 1);
+ psys_particle_on_dm(mesh,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco);
+ BKE_mesh_orco_verts_transform(ob->data, &orco, 1, 1);
BLI_kdtree_insert(tree, p, orco);
}
BLI_kdtree_balance(tree);
- totpart = psys_get_tot_child(scene, psys);
+ totpart = psys_get_tot_child(scene, psys, use_render_params);
cfrom = from = PART_FROM_FACE;
}
else {
distr = part->distr;
- BLI_srandom(31415926 + psys->seed);
+
+ rng = BLI_rng_new_srandom(31415926 + psys->seed);
if (psys->part->use_modifier_stack)
- dm = finaldm;
+ mesh = final_mesh;
else
- dm= CDDM_from_mesh((Mesh*)ob->data);
+ BKE_id_copy_ex(
+ NULL, ob->data, (ID **)&mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
- DM_ensure_tessface(dm);
+ BKE_mesh_tessface_ensure(mesh);
/* we need orco for consistent distributions */
- if (!CustomData_has_layer(&dm->vertData, CD_ORCO))
- DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob));
+ if (!CustomData_has_layer(&mesh->vdata, CD_ORCO))
+ CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob), mesh->totvert);
if (from == PART_FROM_VERT) {
- MVert *mv= dm->getVertDataArray(dm, CD_MVERT);
- float (*orcodata)[3] = dm->getVertDataArray(dm, CD_ORCO);
- int totvert = dm->getNumVerts(dm);
+ MVert *mv = mesh->mvert;
+ float (*orcodata)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO);
+ int totvert = mesh->totvert;
tree=BLI_kdtree_new(totvert);
for (p=0; p<totvert; p++) {
if (orcodata) {
copy_v3_v3(co,orcodata[p]);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co, 1, 1);
}
else
copy_v3_v3(co,mv[p].co);
@@ -940,17 +956,18 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
/* Get total number of emission elements and allocate needed arrays */
- totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm);
+ totelem = (from == PART_FROM_VERT) ? mesh->totvert : mesh->totface;
if (totelem == 0) {
- distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0);
+ distribute_invalid(sim, children ? PART_FROM_CHILD : 0);
if (G.debug & G_DEBUG)
fprintf(stderr,"Particle distribution error: Nothing to emit from!\n");
- if (dm != finaldm) dm->release(dm);
+ if (mesh != final_mesh) BKE_id_free(NULL, mesh);
BLI_kdtree_free(tree);
+ BLI_rng_free(rng);
return 0;
}
@@ -960,37 +977,37 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
jitter_offset = MEM_callocN(sizeof(float) * totelem, "particle_distribution_jitoff");
/* Calculate weights from face areas */
- if ((part->flag&PART_EDISTR || children) && from != PART_FROM_VERT) {
+ if ((part->flag & PART_EDISTR || children) && from != PART_FROM_VERT) {
MVert *v1, *v2, *v3, *v4;
float totarea=0.f, co1[3], co2[3], co3[3], co4[3];
float (*orcodata)[3];
- orcodata= dm->getVertDataArray(dm, CD_ORCO);
+ orcodata = CustomData_get_layer(&mesh->vdata, CD_ORCO);
for (i=0; i<totelem; i++) {
- MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
+ MFace *mf = &mesh->mface[i];
if (orcodata) {
copy_v3_v3(co1, orcodata[mf->v1]);
copy_v3_v3(co2, orcodata[mf->v2]);
copy_v3_v3(co3, orcodata[mf->v3]);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co1, 1, 1);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co2, 1, 1);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co3, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co1, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co2, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co3, 1, 1);
if (mf->v4) {
copy_v3_v3(co4, orcodata[mf->v4]);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co4, 1, 1);
+ BKE_mesh_orco_verts_transform(ob->data, &co4, 1, 1);
}
}
else {
- v1= (MVert*)dm->getVertData(dm,mf->v1,CD_MVERT);
- v2= (MVert*)dm->getVertData(dm,mf->v2,CD_MVERT);
- v3= (MVert*)dm->getVertData(dm,mf->v3,CD_MVERT);
+ v1 = &mesh->mvert[mf->v1];
+ v2 = &mesh->mvert[mf->v2];
+ v3 = &mesh->mvert[mf->v3];
copy_v3_v3(co1, v1->co);
copy_v3_v3(co2, v2->co);
copy_v3_v3(co3, v3->co);
if (mf->v4) {
- v4= (MVert*)dm->getVertData(dm,mf->v4,CD_MVERT);
+ v4 = &mesh->mvert[mf->v4];
copy_v3_v3(co4, v4->co);
}
}
@@ -1017,7 +1034,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
/* Calculate weights from vgroup */
- vweight = psys_cache_vgroup(dm,psys,PSYS_VG_DENSITY);
+ vweight = psys_cache_vgroup(mesh,psys,PSYS_VG_DENSITY);
if (vweight) {
if (from==PART_FROM_VERT) {
@@ -1026,7 +1043,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
}
else { /* PART_FROM_FACE / PART_FROM_VOLUME */
for (i=0;i<totelem; i++) {
- MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
+ MFace *mf = &mesh->mface[i];
tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
if (mf->v4) {
@@ -1087,11 +1104,11 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
totmapped = i_mapped;
/* Finally assign elements to particles */
- if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) {
+ if (part->flag & PART_TRAND) {
for (p = 0; p < totpart; p++) {
/* In theory element_sum[totmapped - 1] should be 1.0,
* but due to float errors this is not necessarily always true, so scale pos accordingly. */
- const float pos = BLI_frand() * element_sum[totmapped - 1];
+ const float pos = BLI_rng_get_float(rng) * element_sum[totmapped - 1];
const int eidx = distribute_binary_search(element_sum, totmapped, pos);
particle_element[p] = element_map[eidx];
BLI_assert(pos <= element_sum[eidx]);
@@ -1129,12 +1146,12 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
int *orig_index = NULL;
if (from == PART_FROM_VERT) {
- if (dm->numVertData)
- orig_index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ if (mesh->totvert)
+ orig_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
}
else {
- if (dm->numTessFaceData)
- orig_index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ if (mesh->totface)
+ orig_index = CustomData_get_layer(&mesh->fdata, CD_ORIGINDEX);
}
if (orig_index) {
@@ -1177,14 +1194,15 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
ctx->maxweight= maxweight;
ctx->cfrom= cfrom;
ctx->distr= distr;
- ctx->dm= dm;
+ ctx->mesh= mesh;
ctx->tpars= tpars;
if (children) {
- totpart= psys_render_simplify_distribution(ctx, totpart);
alloc_child_particles(psys, totpart);
}
+ BLI_rng_free(rng);
+
return 1;
}
@@ -1202,7 +1220,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
TaskPool *task_pool;
ParticleThreadContext ctx;
ParticleTask *tasks;
- DerivedMesh *finaldm = sim->psmd->dm_final;
+ Mesh *final_mesh = sim->psmd->mesh_final;
int i, totpart, numtasks;
/* create a task pool for distribution tasks */
@@ -1227,10 +1245,10 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
BLI_task_pool_free(task_pool);
- psys_calc_dmcache(sim->ob, finaldm, sim->psmd->dm_deformed, sim->psys);
+ psys_calc_dmcache(sim->ob, final_mesh, sim->psmd->mesh_original, sim->psys);
- if (ctx.dm != finaldm)
- ctx.dm->release(ctx.dm);
+ if (ctx.mesh != final_mesh)
+ BKE_id_free(NULL, ctx.mesh);
psys_tasks_free(tasks, numtasks);
@@ -1240,7 +1258,7 @@ static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
/* ready for future use, to emit particles without geometry */
static void distribute_particles_on_shape(ParticleSimulationData *sim, int UNUSED(from))
{
- distribute_invalid(sim->scene, sim->psys, 0);
+ distribute_invalid(sim, 0);
fprintf(stderr,"Shape emission not yet possible!\n");
}
@@ -1251,7 +1269,7 @@ void distribute_particles(ParticleSimulationData *sim, int from)
int distr_error=0;
if (psmd) {
- if (psmd->dm_final)
+ if (psmd->mesh_final)
distribute_particles_on_dm(sim, from);
else
distr_error=1;
@@ -1260,250 +1278,8 @@ void distribute_particles(ParticleSimulationData *sim, int from)
distribute_particles_on_shape(sim, from);
if (distr_error) {
- distribute_invalid(sim->scene, sim->psys, from);
+ distribute_invalid(sim, from);
fprintf(stderr,"Particle distribution error!\n");
}
}
-
-/* ======== Simplify ======== */
-
-static float psys_render_viewport_falloff(double rate, float dist, float width)
-{
- return pow(rate, dist / width);
-}
-
-static float psys_render_projected_area(ParticleSystem *psys, const float center[3], float area, double vprate, float *viewport)
-{
- ParticleRenderData *data = psys->renderdata;
- float co[4], view[3], ortho1[3], ortho2[3], w, dx, dy, radius;
-
- /* transform to view space */
- copy_v3_v3(co, center);
- co[3] = 1.0f;
- mul_m4_v4(data->viewmat, co);
-
- /* compute two vectors orthogonal to view vector */
- normalize_v3_v3(view, co);
- ortho_basis_v3v3_v3(ortho1, ortho2, view);
-
- /* compute on screen minification */
- w = co[2] * data->winmat[2][3] + data->winmat[3][3];
- dx = data->winx * ortho2[0] * data->winmat[0][0];
- dy = data->winy * ortho2[1] * data->winmat[1][1];
- w = sqrtf(dx * dx + dy * dy) / w;
-
- /* w squared because we are working with area */
- area = area * w * w;
-
- /* viewport of the screen test */
-
- /* project point on screen */
- mul_m4_v4(data->winmat, co);
- if (co[3] != 0.0f) {
- co[0] = 0.5f * data->winx * (1.0f + co[0] / co[3]);
- co[1] = 0.5f * data->winy * (1.0f + co[1] / co[3]);
- }
-
- /* screen space radius */
- radius = sqrtf(area / (float)M_PI);
-
- /* make smaller using fallof once over screen edge */
- *viewport = 1.0f;
-
- if (co[0] + radius < 0.0f)
- *viewport *= psys_render_viewport_falloff(vprate, -(co[0] + radius), data->winx);
- else if (co[0] - radius > data->winx)
- *viewport *= psys_render_viewport_falloff(vprate, (co[0] - radius) - data->winx, data->winx);
-
- if (co[1] + radius < 0.0f)
- *viewport *= psys_render_viewport_falloff(vprate, -(co[1] + radius), data->winy);
- else if (co[1] - radius > data->winy)
- *viewport *= psys_render_viewport_falloff(vprate, (co[1] - radius) - data->winy, data->winy);
-
- return area;
-}
-
-/* BMESH_TODO, for orig face data, we need to use MPoly */
-static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
-{
- DerivedMesh *dm = ctx->dm;
- Mesh *me = (Mesh *)(ctx->sim.ob->data);
- MFace *mf, *mface;
- MVert *mvert;
- ParticleRenderData *data;
- ParticleRenderElem *elems, *elem;
- ParticleSettings *part = ctx->sim.psys->part;
- float *facearea, (*facecenter)[3], size[3], fac, powrate, scaleclamp;
- float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport;
- double vprate;
- int *facetotvert;
- int a, b, totorigface, totface, newtot, skipped;
-
- /* double lookup */
- const int *index_mf_to_mpoly;
- const int *index_mp_to_orig;
-
- if (part->ren_as != PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND))
- return tot;
- if (!ctx->sim.psys->renderdata)
- return tot;
-
- data = ctx->sim.psys->renderdata;
- if (data->timeoffset)
- return 0;
- if (!(part->simplify_flag & PART_SIMPLIFY_ENABLE))
- return tot;
-
- mvert = dm->getVertArray(dm);
- mface = dm->getTessFaceArray(dm);
- totface = dm->getNumTessFaces(dm);
- totorigface = me->totpoly;
-
- if (totface == 0 || totorigface == 0)
- return tot;
-
- index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
-
- facearea = MEM_callocN(sizeof(float) * totorigface, "SimplifyFaceArea");
- facecenter = MEM_callocN(sizeof(float[3]) * totorigface, "SimplifyFaceCenter");
- facetotvert = MEM_callocN(sizeof(int) * totorigface, "SimplifyFaceArea");
- elems = MEM_callocN(sizeof(ParticleRenderElem) * totorigface, "SimplifyFaceElem");
-
- if (data->elems)
- MEM_freeN(data->elems);
-
- data->do_simplify = true;
- data->elems = elems;
- data->index_mf_to_mpoly = index_mf_to_mpoly;
- data->index_mp_to_orig = index_mp_to_orig;
-
- /* compute number of children per original face */
- for (a = 0; a < tot; a++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
- if (b != ORIGINDEX_NONE) {
- elems[b].totchild++;
- }
- }
-
- /* compute areas and centers of original faces */
- for (mf = mface, a = 0; a < totface; a++, mf++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
-
- if (b != ORIGINDEX_NONE) {
- copy_v3_v3(co1, mvert[mf->v1].co);
- copy_v3_v3(co2, mvert[mf->v2].co);
- copy_v3_v3(co3, mvert[mf->v3].co);
-
- add_v3_v3(facecenter[b], co1);
- add_v3_v3(facecenter[b], co2);
- add_v3_v3(facecenter[b], co3);
-
- if (mf->v4) {
- copy_v3_v3(co4, mvert[mf->v4].co);
- add_v3_v3(facecenter[b], co4);
- facearea[b] += area_quad_v3(co1, co2, co3, co4);
- facetotvert[b] += 4;
- }
- else {
- facearea[b] += area_tri_v3(co1, co2, co3);
- facetotvert[b] += 3;
- }
- }
- }
-
- for (a = 0; a < totorigface; a++)
- if (facetotvert[a] > 0)
- mul_v3_fl(facecenter[a], 1.0f / facetotvert[a]);
-
- /* for conversion from BU area / pixel area to reference screen size */
- BKE_mesh_texspace_get(me, 0, 0, size);
- fac = ((size[0] + size[1] + size[2]) / 3.0f) / part->simplify_refsize;
- fac = fac * fac;
-
- powrate = log(0.5f) / log(part->simplify_rate * 0.5f);
- if (part->simplify_flag & PART_SIMPLIFY_VIEWPORT)
- vprate = pow(1.0f - part->simplify_viewport, 5.0);
- else
- vprate = 1.0;
-
- /* set simplification parameters per original face */
- for (a = 0, elem = elems; a < totorigface; a++, elem++) {
- area = psys_render_projected_area(ctx->sim.psys, facecenter[a], facearea[a], vprate, &viewport);
- arearatio = fac * area / facearea[a];
-
- if ((arearatio < 1.0f || viewport < 1.0f) && elem->totchild) {
- /* lambda is percentage of elements to keep */
- lambda = (arearatio < 1.0f) ? powf(arearatio, powrate) : 1.0f;
- lambda *= viewport;
-
- lambda = MAX2(lambda, 1.0f / elem->totchild);
-
- /* compute transition region */
- t = part->simplify_transition;
- elem->t = (lambda - t < 0.0f) ? lambda : (lambda + t > 1.0f) ? 1.0f - lambda : t;
- elem->reduce = 1;
-
- /* scale at end and beginning of the transition region */
- elem->scalemax = (lambda + t < 1.0f) ? 1.0f / lambda : 1.0f / (1.0f - elem->t * elem->t / t);
- elem->scalemin = (lambda + t < 1.0f) ? 0.0f : elem->scalemax * (1.0f - elem->t / t);
-
- elem->scalemin = sqrtf(elem->scalemin);
- elem->scalemax = sqrtf(elem->scalemax);
-
- /* clamp scaling */
- scaleclamp = (float)min_ii(elem->totchild, 10);
- elem->scalemin = MIN2(scaleclamp, elem->scalemin);
- elem->scalemax = MIN2(scaleclamp, elem->scalemax);
-
- /* extend lambda to include transition */
- lambda = lambda + elem->t;
- if (lambda > 1.0f)
- lambda = 1.0f;
- }
- else {
- lambda = arearatio;
-
- elem->scalemax = 1.0f; //sqrt(lambda);
- elem->scalemin = 1.0f; //sqrt(lambda);
- elem->reduce = 0;
- }
-
- elem->lambda = lambda;
- elem->scalemin = sqrtf(elem->scalemin);
- elem->scalemax = sqrtf(elem->scalemax);
- elem->curchild = 0;
- }
-
- MEM_freeN(facearea);
- MEM_freeN(facecenter);
- MEM_freeN(facetotvert);
-
- /* move indices and set random number skipping */
- ctx->skip = MEM_callocN(sizeof(int) * tot, "SimplificationSkip");
-
- skipped = 0;
- for (a = 0, newtot = 0; a < tot; a++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
-
- if (b != ORIGINDEX_NONE) {
- if (elems[b].curchild++ < ceil(elems[b].lambda * elems[b].totchild)) {
- ctx->index[newtot] = ctx->index[a];
- ctx->skip[newtot] = skipped;
- skipped = 0;
- newtot++;
- }
- else skipped++;
- }
- else skipped++;
- }
-
- for (a = 0, elem = elems; a < totorigface; a++, elem++)
- elem->curchild = 0;
-
- return newtot;
-}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 8def945ca7c..c363d9f29c2 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -70,15 +70,16 @@
#include "BKE_animsys.h"
#include "BKE_boids.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_collision.h"
#include "BKE_colortools.h"
#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_main.h"
#include "BKE_particle.h"
-#include "BKE_DerivedMesh.h"
+#include "BKE_collection.h"
#include "BKE_object.h"
#include "BKE_material.h"
#include "BKE_cloth.h"
@@ -88,12 +89,14 @@
#include "BKE_modifier.h"
#include "BKE_scene.h"
#include "BKE_bvhutils.h"
-#include "BKE_depsgraph.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_physics.h"
+#include "DEG_depsgraph_query.h"
#include "PIL_time.h"
#include "RE_shader_ext.h"
-#include "DEG_depsgraph.h"
/* fluid sim particle import */
#ifdef WITH_MOD_FLUID
@@ -121,11 +124,11 @@ static int particles_are_dynamic(ParticleSystem *psys)
return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID);
}
-float psys_get_current_display_percentage(ParticleSystem *psys)
+float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_render_params)
{
ParticleSettings *part=psys->part;
- if ((psys->renderdata && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
+ if ((use_render_params && !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
(part->child_nbr && part->childtype) || /* display percentage applies to children */
(psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */
{
@@ -287,31 +290,31 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
}
}
-int psys_get_child_number(Scene *scene, ParticleSystem *psys)
+int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params)
{
int nbr;
if (!psys->part->childtype)
return 0;
- if (psys->renderdata)
+ if (use_render_params)
nbr= psys->part->ren_child_nbr;
else
nbr= psys->part->child_nbr;
- return get_render_child_particle_number(&scene->r, nbr, psys->renderdata != NULL);
+ return get_render_child_particle_number(&scene->r, nbr, use_render_params);
}
-int psys_get_tot_child(Scene *scene, ParticleSystem *psys)
+int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params)
{
- return psys->totpart*psys_get_child_number(scene, psys);
+ return psys->totpart*psys_get_child_number(scene, psys, use_render_params);
}
/************************************************/
/* Distribution */
/************************************************/
-void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deformed, ParticleSystem *psys)
+void psys_calc_dmcache(Object *ob, Mesh *mesh_final, Mesh *mesh_original, ParticleSystem *psys)
{
/* use for building derived mesh mapping info:
*
@@ -324,13 +327,13 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
PARTICLE_P;
/* CACHE LOCATIONS */
- if (!dm_final->deformedOnly) {
- /* Will use later to speed up subsurf/derivedmesh */
+ if (!mesh_final->runtime.deformed_only) {
+ /* Will use later to speed up subsurf/evaluated mesh. */
LinkNode *node, *nodedmelem, **nodearray;
int totdmelem, totelem, i, *origindex, *origindex_poly = NULL;
if (psys->part->from == PART_FROM_VERT) {
- totdmelem= dm_final->getNumVerts(dm_final);
+ totdmelem = mesh_final->totvert;
if (use_modifier_stack) {
totelem= totdmelem;
@@ -338,11 +341,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
}
else {
totelem= me->totvert;
- origindex= dm_final->getVertDataArray(dm_final, CD_ORIGINDEX);
+ origindex = CustomData_get_layer(&mesh_final->vdata, CD_ORIGINDEX);
}
}
else { /* FROM_FACE/FROM_VOLUME */
- totdmelem= dm_final->getNumTessFaces(dm_final);
+ totdmelem= mesh_final->totface;
if (use_modifier_stack) {
totelem= totdmelem;
@@ -350,11 +353,11 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
origindex_poly= NULL;
}
else {
- totelem = dm_deformed->getNumTessFaces(dm_deformed);
- origindex = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX);
+ totelem = mesh_original->totface;
+ origindex = CustomData_get_layer(&mesh_final->fdata, CD_ORIGINDEX);
/* for face lookups we need the poly origindex too */
- origindex_poly= dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX);
+ origindex_poly = CustomData_get_layer(&mesh_final->pdata, CD_ORIGINDEX);
if (origindex_poly == NULL) {
origindex= NULL;
}
@@ -414,7 +417,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm_final, DerivedMesh *dm_deform
pa->num_dmcache = DMCACHE_NOTFOUND;
}
else { /* FROM_FACE/FROM_VOLUME */
- pa->num_dmcache = psys_particle_dm_face_lookup(dm_final, dm_deformed, pa->num, pa->fuv, nodearray);
+ pa->num_dmcache = psys_particle_dm_face_lookup(mesh_final, mesh_original, pa->num, pa->fuv, nodearray);
}
}
}
@@ -438,7 +441,7 @@ void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData
{
memset(ctx, 0, sizeof(ParticleThreadContext));
ctx->sim = *sim;
- ctx->dm = ctx->sim.psmd->dm_final;
+ ctx->mesh = ctx->sim.psmd->mesh_final;
ctx->ma = give_current_material(sim->ob, sim->psys->part->omat);
}
@@ -513,7 +516,6 @@ void psys_thread_context_free(ParticleThreadContext *ctx)
if (ctx->jitoff) MEM_freeN(ctx->jitoff);
if (ctx->weight) MEM_freeN(ctx->weight);
if (ctx->index) MEM_freeN(ctx->index);
- if (ctx->skip) MEM_freeN(ctx->skip);
if (ctx->seams) MEM_freeN(ctx->seams);
//if (ctx->vertpart) MEM_freeN(ctx->vertpart);
BLI_kdtree_free(ctx->tree);
@@ -704,9 +706,9 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic
/* get birth location from object */
if (use_tangents)
- psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0,0);
+ psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,utan,vtan,0);
else
- psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0,0);
+ psys_particle_on_emitter(sim->psmd, part->from,pa->num, pa->num_dmcache, pa->fuv,pa->foffset,loc,nor,0,0,0);
/* get possible textural influence */
psys_get_texture(sim, pa, &ptex, PAMAP_IVEL, cfra);
@@ -990,14 +992,14 @@ void psys_get_birth_coords(ParticleSimulationData *sim, ParticleData *pa, Partic
}
/* recursively evaluate emitter parent anim at cfra */
-static void evaluate_emitter_anim(Scene *scene, Object *ob, float cfra)
+static void evaluate_emitter_anim(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra)
{
if (ob->parent)
- evaluate_emitter_anim(scene, ob->parent, cfra);
+ evaluate_emitter_anim(depsgraph, scene, ob->parent, cfra);
/* we have to force RECALC_ANIM here since where_is_objec_time only does drivers */
- BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM);
- BKE_object_where_is_calc_time(scene, ob, cfra);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &ob->id, ob->adt, cfra, ADT_RECALC_ANIM);
+ BKE_object_where_is_calc_time(depsgraph, scene, ob, cfra);
}
/* sets particle to the emitter surface with initial velocity & rotation */
@@ -1011,7 +1013,7 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
/* get precise emitter matrix if particle is born */
if (part->type != PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
- evaluate_emitter_anim(sim->scene, sim->ob, pa->time);
+ evaluate_emitter_anim(sim->depsgraph, sim->scene, sim->ob, pa->time);
psys->flag |= PSYS_OB_ANIM_RESTORE;
}
@@ -1145,7 +1147,8 @@ static void set_keyed_keys(ParticleSimulationData *sim)
int totpart = psys->totpart, k, totkeys = psys->totkeyed;
int keyed_flag = 0;
- ksim.scene= sim->scene;
+ ksim.depsgraph = sim->depsgraph;
+ ksim.scene = sim->scene;
/* no proper targets so let's clear and bail out */
if (psys->totkeyed==0) {
@@ -1305,9 +1308,10 @@ void psys_update_particle_tree(ParticleSystem *psys, float cfra)
static void psys_update_effectors(ParticleSimulationData *sim)
{
- pdEndEffectors(&sim->psys->effectors);
- sim->psys->effectors = pdInitEffectors(sim->scene, sim->ob, sim->psys,
- sim->psys->part->effector_weights, true);
+ BKE_effectors_free(sim->psys->effectors);
+ sim->psys->effectors = BKE_effectors_create(sim->depsgraph,
+ sim->ob, sim->psys,
+ sim->psys->part->effector_weights);
precalc_guides(sim, sim->psys->effectors);
}
@@ -2059,11 +2063,12 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo
ParticleSettings *part = sim->psys->part;
ParticleData *pa = efdata->pa;
EffectedPoint epoint;
+ RNG *rng = sim->rng;
/* add effectors */
pd_point_from_particle(efdata->sim, efdata->pa, state, &epoint);
if (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR)
- pdDoEffectors(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
+ BKE_effectors_apply(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
mul_v3_fl(force, efdata->ptex.field);
mul_v3_fl(impulse, efdata->ptex.field);
@@ -2074,9 +2079,9 @@ static void basic_force_cb(void *efdata_v, ParticleKey *state, float *force, flo
/* brownian force */
if (part->brownfac != 0.0f) {
- force[0] += (BLI_frand()-0.5f) * part->brownfac;
- force[1] += (BLI_frand()-0.5f) * part->brownfac;
- force[2] += (BLI_frand()-0.5f) * part->brownfac;
+ force[0] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
+ force[1] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
+ force[2] += (BLI_rng_get_float(rng)-0.5f) * part->brownfac;
}
if (part->flag & PART_ROT_DYN && epoint.ave)
@@ -2127,7 +2132,7 @@ static void basic_integrate(ParticleSimulationData *sim, int p, float dfra, floa
tkey.time=pa->state.time;
if (part->type != PART_HAIR) {
- if (do_guides(sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
+ if (do_guides(sim->depsgraph, sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
copy_v3_v3(pa->state.co,tkey.co);
/* guides don't produce valid velocity */
sub_v3_v3v3(pa->state.vel, tkey.co, pa->prev_state.co);
@@ -2647,16 +2652,17 @@ static int collision_detect(ParticleData *pa, ParticleCollision *col, BVHTreeRay
return hit->index >= 0;
}
-static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation)
+static int collision_response(ParticleSimulationData *sim, ParticleData *pa, ParticleCollision *col, BVHTreeRayHit *hit, int kill, int dynamic_rotation)
{
ParticleCollisionElement *pce = &col->pce;
PartDeflect *pd = col->hit->pd;
+ RNG *rng = sim->rng;
float co[3]; /* point of collision */
float x = hit->dist/col->original_ray_length; /* location factor of collision between this iteration */
float f = col->f + x * (1.0f - col->f); /* time factor of collision between timestep */
float dt1 = (f - col->f) * col->total_time; /* time since previous collision (in seconds) */
float dt2 = (1.0f - f) * col->total_time; /* time left after collision (in seconds) */
- int through = (BLI_frand() < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */
+ int through = (BLI_rng_get_float(rng) < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */
/* calculate exact collision location */
interp_v3_v3v3(co, col->co1, col->co2, x);
@@ -2681,8 +2687,8 @@ static int collision_response(ParticleData *pa, ParticleCollision *col, BVHTreeR
float v0_tan[3];/* tangential component of v0 */
float vc_tan[3];/* tangential component of collision surface velocity */
float v0_dot, vc_dot;
- float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_frand() - 0.5f);
- float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_frand() - 0.5f);
+ float damp = pd->pdef_damp + pd->pdef_rdamp * 2 * (BLI_rng_get_float(rng) - 0.5f);
+ float frict = pd->pdef_frict + pd->pdef_rfrict * 2 * (BLI_rng_get_float(rng) - 0.5f);
float distance, nor[3], dot;
CLAMP(damp,0.0f, 1.0f);
@@ -2892,7 +2898,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
if (collision_count == PARTICLE_COLLISION_MAX_COLLISIONS)
collision_fail(pa, &col);
- else if (collision_response(pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0)
+ else if (collision_response(sim, pa, &col, &hit, part->flag & PART_DIE_ON_COL, part->flag & PART_ROT_DYN)==0)
return;
}
else
@@ -2908,10 +2914,9 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
- Base *base;
int distr=0, alloc=0, skip=0;
- if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET)
+ if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys, use_render_params)) || psys->recalc&PSYS_RECALC_RESET)
alloc=1;
if (alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT)))
@@ -2921,7 +2926,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
if (alloc)
realloc_particles(sim, sim->psys->totpart);
- if (psys_get_tot_child(sim->scene, psys)) {
+ if (psys_get_tot_child(sim->scene, psys, use_render_params)) {
/* don't generate children while computing the hair keys */
if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
distribute_particles(sim, PART_FROM_CHILD);
@@ -2938,12 +2943,13 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
skip = 1; /* only hair, keyed and baked stuff can have paths */
else if (part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)))
skip = 1; /* particle visualization must be set as path */
- else if (!psys->renderdata) {
+ else if (DEG_get_mode(sim->depsgraph) != DAG_EVAL_RENDER) {
if (part->draw_as != PART_DRAW_REND)
skip = 1; /* draw visualization */
else if (psys->pointcache->flag & PTCACHE_BAKING)
skip = 1; /* no need to cache paths while baking dynamics */
- else if (psys_in_edit_mode(sim->scene, psys)) {
+
+ else if (psys_in_edit_mode(sim->depsgraph, psys)) {
if ((pset->flag & PE_DRAW_PART)==0)
skip = 1;
else if (part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0)
@@ -2953,15 +2959,19 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons
/* particle instance modifier with "path" option need cached paths even if particle system doesn't */
- for (base = sim->scene->base.first; base; base= base->next) {
- ModifierData *md = modifiers_findByType(base->object, eModifierType_ParticleInstance);
- if (md) {
- ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
- if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) {
- skip = 0;
- break;
+ if (skip) {
+ FOREACH_SCENE_OBJECT_BEGIN(sim->scene, ob)
+ {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_ParticleInstance);
+ if (md) {
+ ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
+ if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) {
+ skip = 0;
+ break;
+ }
}
}
+ FOREACH_SCENE_OBJECT_END;
}
if (!skip) {
@@ -3021,11 +3031,11 @@ static MDeformVert *hair_set_pinning(MDeformVert *dvert, float weight)
return dvert;
}
-static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int totedge, DerivedMesh **r_dm, ClothHairData **r_hairdata)
+static void hair_create_input_mesh(ParticleSimulationData *sim, int totpoint, int totedge, Mesh **r_mesh, ClothHairData **r_hairdata)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
- DerivedMesh *dm;
+ Mesh *mesh;
ClothHairData *hairdata;
MVert *mvert;
MEdge *medge;
@@ -3037,14 +3047,15 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
float max_length;
float hair_radius;
- dm = *r_dm;
- if (!dm) {
- *r_dm = dm = CDDM_new(totpoint, totedge, 0, 0, 0);
- DM_add_vert_layer(dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
+ mesh = *r_mesh;
+ if (!mesh) {
+ *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0);
+ CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert);
+ BKE_mesh_update_customdata_pointers(mesh, false);
}
- mvert = CDDM_get_verts(dm);
- medge = CDDM_get_edges(dm);
- dvert = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
+ mvert = mesh->mvert;
+ medge = mesh->medge;
+ dvert = mesh->dvert;
hairdata = *r_hairdata;
if (!hairdata) {
@@ -3079,7 +3090,7 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
pa->hair_index = hair_index;
use_hair = psys_hair_use_simulation(pa, max_length);
- psys_mat_hair_to_object(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_object(sim->ob, sim->psmd->mesh_final, psys->part->from, pa, hairmat);
mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
normalize_m4(root_mat);
@@ -3159,8 +3170,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
if (!psys->clmd) {
psys->clmd = (ClothModifierData*)modifier_new(eModifierType_Cloth);
psys->clmd->sim_parms->goalspring = 0.0f;
- psys->clmd->sim_parms->vel_damping = 1.0f;
- psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_GOAL|CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
+ psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_RESIST_SPRING_COMPRESS;
psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
}
@@ -3176,26 +3186,26 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
}
realloc_roots = false; /* whether hair root info array has to be reallocated */
- if (psys->hair_in_dm) {
- DerivedMesh *dm = psys->hair_in_dm;
- if (totpoint != dm->getNumVerts(dm) || totedge != dm->getNumEdges(dm)) {
- dm->release(dm);
- psys->hair_in_dm = NULL;
+ if (psys->hair_in_mesh) {
+ Mesh *mesh = psys->hair_in_mesh;
+ if (totpoint != mesh->totvert || totedge != mesh->totedge) {
+ BKE_id_free(NULL, mesh);
+ psys->hair_in_mesh = NULL;
realloc_roots = true;
}
}
- if (!psys->hair_in_dm || !psys->clmd->hairdata || realloc_roots) {
+ if (!psys->hair_in_mesh || !psys->clmd->hairdata || realloc_roots) {
if (psys->clmd->hairdata) {
MEM_freeN(psys->clmd->hairdata);
psys->clmd->hairdata = NULL;
}
}
- hair_create_input_dm(sim, totpoint, totedge, &psys->hair_in_dm, &psys->clmd->hairdata);
+ hair_create_input_mesh(sim, totpoint, totedge, &psys->hair_in_mesh, &psys->clmd->hairdata);
- if (psys->hair_out_dm)
- psys->hair_out_dm->release(psys->hair_out_dm);
+ if (psys->hair_out_mesh)
+ BKE_id_free(NULL, psys->hair_out_mesh);
psys->clmd->point_cache = psys->pointcache;
/* for hair sim we replace the internal cloth effector weights temporarily
@@ -3204,13 +3214,16 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
clmd_effweights = psys->clmd->sim_parms->effector_weights;
psys->clmd->sim_parms->effector_weights = psys->part->effector_weights;
- deformedVerts = MEM_mallocN(sizeof(*deformedVerts) * psys->hair_in_dm->getNumVerts(psys->hair_in_dm), "do_hair_dynamics vertexCos");
- psys->hair_out_dm = CDDM_copy(psys->hair_in_dm);
- psys->hair_out_dm->getVertCos(psys->hair_out_dm, deformedVerts);
-
- clothModifier_do(psys->clmd, sim->scene, sim->ob, psys->hair_in_dm, deformedVerts);
-
- CDDM_apply_vert_coords(psys->hair_out_dm, deformedVerts);
+ BKE_id_copy_ex(
+ NULL, &psys->hair_in_mesh->id, (ID **)&psys->hair_out_mesh,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+ deformedVerts = BKE_mesh_vertexCos_get(psys->hair_out_mesh, NULL);
+ clothModifier_do(psys->clmd, sim->depsgraph, sim->scene, sim->ob, psys->hair_in_mesh, deformedVerts);
+ BKE_mesh_apply_vert_coords(psys->hair_out_mesh, deformedVerts);
MEM_freeN(deformedVerts);
@@ -3222,7 +3235,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_re
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys);
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
LOOP_PARTICLES {
pa->size = part->size;
@@ -3237,7 +3250,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_re
if (psys->recalc & PSYS_RECALC_RESET) {
/* need this for changing subsurf levels */
- psys_calc_dmcache(sim->ob, sim->psmd->dm_final, sim->psmd->dm_deformed, psys);
+ psys_calc_dmcache(sim->ob, sim->psmd->mesh_final, sim->psmd->mesh_original, psys);
if (psys->clmd)
cloth_free_modifier(psys->clmd);
@@ -3284,7 +3297,7 @@ static void save_hair(ParticleSimulationData *sim, float UNUSED(cfra))
if (pa->totkey) {
sub_v3_v3(key->co, root->co);
- psys_vec_rot_to_face(sim->psmd->dm_final, pa, key->co);
+ psys_vec_rot_to_face(sim->psmd->mesh_final, pa, key->co);
}
key->time = pa->state.time;
@@ -3494,7 +3507,6 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part=psys->part;
- RNG *rng;
BoidBrainData bbd;
ParticleTexture ptex;
PARTICLE_P;
@@ -3521,14 +3533,13 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
return;
}
- BLI_srandom(31415926 + (int)cfra + psys->seed);
/* for now do both, boids us 'rng' */
- rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed);
+ sim->rng = BLI_rng_new_srandom(31415926 + (int)cfra + psys->seed);
psys_update_effectors(sim);
if (part->type != PART_HAIR)
- sim->colliders = get_collider_cache(sim->scene, sim->ob, part->collision_group);
+ sim->colliders = BKE_collider_cache_create(sim->depsgraph, sim->ob, part->collision_group);
/* initialize physics type specific stuff */
switch (part->phystype) {
@@ -3540,7 +3551,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
bbd.cfra = cfra;
bbd.dfra = dfra;
bbd.timestep = timestep;
- bbd.rng = rng;
+ bbd.rng = sim->rng;
psys_update_particle_tree(psys, cfra);
@@ -3735,16 +3746,18 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
pa->state.time=cfra;
}
- free_collider_cache(&sim->colliders);
- BLI_rng_free(rng);
+ BKE_collider_cache_free(&sim->colliders);
+ BLI_rng_free(sim->rng);
+ sim->rng = NULL;
}
-static void update_children(ParticleSimulationData *sim)
+
+static void update_children(ParticleSimulationData *sim, const bool use_render_params)
{
if ((sim->psys->part->type == PART_HAIR) && (sim->psys->flag & PSYS_HAIR_DONE)==0)
/* don't generate children while growing hair - waste of time */
psys_free_children(sim->psys);
else if (sim->psys->part->childtype) {
- if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys))
+ if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys, use_render_params))
distribute_particles(sim, PART_FROM_CHILD);
else {
/* Children are up to date, nothing to do. */
@@ -3754,7 +3767,7 @@ static void update_children(ParticleSimulationData *sim)
psys_free_children(sim->psys);
}
/* updates cached particles' alive & other flags etc..*/
-static void cached_step(ParticleSimulationData *sim, float cfra)
+static void cached_step(ParticleSimulationData *sim, float cfra, const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
@@ -3764,7 +3777,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
psys_update_effectors(sim);
- disp= psys_get_current_display_percentage(psys);
+ disp= psys_get_current_display_percentage(psys, use_render_params);
LOOP_PARTICLES {
psys_get_texture(sim, pa, &ptex, PAMAP_SIZE, cfra);
@@ -3800,7 +3813,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
}
static void particles_fluid_step(
- Main *bmain, ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params)
+ ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params)
{
ParticleSystem *psys = sim->psys;
if (psys->particles) {
@@ -3831,7 +3844,7 @@ static void particles_fluid_step(
// ok, start loading
BLI_join_dirfile(filename, sizeof(filename), fss->surfdataPath, OB_FLUIDSIM_SURF_PARTICLES_FNAME);
- BLI_path_abs(filename, modifier_path_relbase(bmain, sim->ob));
+ BLI_path_abs(filename, modifier_path_relbase_from_global(sim->ob));
BLI_path_frame(filename, curFrame, 0); // fixed #frame-no
@@ -3905,7 +3918,7 @@ static void particles_fluid_step(
} // fluid sim particles done
}
#else
- UNUSED_VARS(bmain, use_render_params);
+ UNUSED_VARS(use_render_params);
#endif // WITH_MOD_FLUID
}
@@ -3987,8 +4000,8 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
int cache_result = BKE_ptcache_read(pid, cache_cfra, true);
if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) {
- cached_step(sim, cfra);
- update_children(sim);
+ cached_step(sim, cfra, use_render_params);
+ update_children(sim, use_render_params);
psys_update_path_cache(sim, cfra, use_render_params);
BKE_ptcache_validate(cache, (int)cache_cfra);
@@ -4005,7 +4018,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
}
else if (cache_result == PTCACHE_READ_OLD) {
psys->cfra = (float)cache->simframe;
- cached_step(sim, psys->cfra);
+ cached_step(sim, psys->cfra, use_render_params);
}
/* if on second frame, write cache for first frame */
@@ -4017,7 +4030,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
/* 3. do dynamics */
/* set particles to be not calculated TODO: can't work with pointcache */
- disp= psys_get_current_display_percentage(psys);
+ disp= psys_get_current_display_percentage(psys, use_render_params);
LOOP_PARTICLES {
if (psys_frand(psys, p) > disp)
@@ -4055,9 +4068,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
sim->courant_num = 0.0f;
dynamics_step(sim, cfra+dframe+t_frac - 1.f);
psys->cfra = cfra+dframe+t_frac - 1.f;
-#if 0
- printf("%f,%f,%f,%f\n", cfra+dframe+t_frac - 1.f, t_frac, dt_frac, sim->courant_num);
-#endif
+
if (part->time_flag & PART_TIME_AUTOSF)
update_timestep(psys, sim);
/* Even without AUTOSF dt_frac may not add up to 1.0 due to float precision. */
@@ -4073,7 +4084,7 @@ static void system_step(ParticleSimulationData *sim, float cfra, const bool use_
BKE_ptcache_write(pid, (int)cache_cfra);
}
- update_children(sim);
+ update_children(sim, use_render_params);
/* cleanup */
if (psys->lattice_deform_data) {
@@ -4199,11 +4210,13 @@ static int hair_needs_recalc(ParticleSystem *psys)
/* main particle update call, checks that things are ok on the large scale and
* then advances in to actual particle calculations depending on particle type */
-void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
+void particle_system_update(struct Depsgraph *depsgraph, Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params)
{
ParticleSimulationData sim= {0};
ParticleSettings *part = psys->part;
+ ParticleSystem *psys_orig = psys_orig_get(psys);
float cfra;
+ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
/* drawdata is outdated after ANY change */
if (psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
@@ -4211,12 +4224,13 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
if (!psys_check_enabled(ob, psys, use_render_params))
return;
- cfra= BKE_scene_frame_get(scene);
+ cfra = DEG_get_ctime(depsgraph);
- sim.scene= scene;
- sim.ob= ob;
- sim.psys= psys;
- sim.psmd= psys_get_modifier(ob, psys);
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = psmd;
/* system was already updated from modifier stack */
if (sim.psmd->flag & eParticleSystemFlag_psys_updated) {
@@ -4226,22 +4240,19 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
return;
}
- if (!sim.psmd->dm_final)
+ if (!sim.psmd->mesh_final)
return;
if (part->from != PART_FROM_VERT) {
- DM_ensure_tessface(sim.psmd->dm_final);
+ BKE_mesh_tessface_ensure(sim.psmd->mesh_final);
}
/* execute drivers only, as animation has already been done */
- BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, cfra, ADT_RECALC_DRIVERS);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &part->id, part->adt, cfra, ADT_RECALC_DRIVERS);
/* to verify if we need to restore object afterwards */
psys->flag &= ~PSYS_OB_ANIM_RESTORE;
- if (psys->recalc & PSYS_RECALC_TYPE)
- psys_changed_type(sim.ob, sim.psys);
-
if (psys->recalc & PSYS_RECALC_RESET)
psys->totunexist = 0;
@@ -4264,10 +4275,10 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
free_hair(ob, psys, 0);
- if (psys->edit && psys->free_edit) {
- psys->free_edit(psys->edit);
- psys->edit = NULL;
- psys->free_edit = NULL;
+ if (psys_orig->edit && psys_orig->free_edit) {
+ psys_orig->free_edit(psys_orig->edit);
+ psys_orig->edit = NULL;
+ psys_orig->free_edit = NULL;
}
/* first step is negative so particles get killed and reset */
@@ -4276,7 +4287,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
for (i=0; i<=part->hair_step; i++) {
hcfra=100.0f*(float)i/(float)psys->part->hair_step;
if ((part->flag & PART_HAIR_REGROW)==0)
- BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(depsgraph, scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM);
system_step(&sim, hcfra, use_render_params);
psys->cfra = hcfra;
psys->recalc = 0;
@@ -4295,7 +4306,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
}
case PART_FLUID:
{
- particles_fluid_step(bmain, &sim, (int)cfra, use_render_params);
+ particles_fluid_step(&sim, (int)cfra, use_render_params);
break;
}
default:
@@ -4305,7 +4316,7 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
case PART_PHYS_KEYED:
{
PARTICLE_P;
- float disp = psys_get_current_display_percentage(psys);
+ float disp = psys_get_current_display_percentage(psys, use_render_params);
bool free_unexisting = false;
/* Particles without dynamics haven't been reset yet because they don't use pointcache */
@@ -4359,16 +4370,33 @@ void particle_system_update(Main *bmain, Scene *scene, Object *ob, ParticleSyste
/* make sure emitter is left at correct time (particle emission can change this) */
if (psys->flag & PSYS_OB_ANIM_RESTORE) {
- evaluate_emitter_anim(scene, ob, cfra);
+ evaluate_emitter_anim(depsgraph, scene, ob, cfra);
psys->flag &= ~PSYS_OB_ANIM_RESTORE;
}
+ if (psys_orig->edit) {
+ psys_orig->edit->flags |= PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL;
+ }
+
+ if (DEG_is_active(depsgraph)) {
+ if (psys_orig != psys) {
+ if (psys_orig->edit != NULL &&
+ psys_orig->edit->psys == psys_orig)
+ {
+ psys_orig->edit->psys_eval = psys;
+ psys_orig->edit->psmd_eval = psmd;
+ }
+ psys_orig->flag = psys->flag;
+ }
+ }
+
psys->cfra = cfra;
psys->recalc = 0;
/* save matrix for duplicators, at rendertime the actual dupliobject's matrix is used so don't update! */
- if (psys->renderdata==0)
- invert_m4_m4(psys->imat, ob->obmat);
+ invert_m4_m4(psys->imat, ob->obmat);
+
+ BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
}
/* ID looper */
@@ -4399,10 +4427,16 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func,
/* **** Depsgraph evaluation **** */
-void BKE_particle_system_eval_init(EvaluationContext *UNUSED(eval_ctx),
+void BKE_particle_system_eval_init(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
- DEG_debug_print_eval(__func__, ob->id.name, ob);
+ DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob);
+ for (ParticleSystem *psys = ob->particlesystem.first;
+ psys != NULL;
+ psys = psys->next)
+ {
+ psys->recalc |= (psys->part->id.recalc & DEG_TAG_PSYS_ALL);
+ }
BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 746e8b63a18..413f0407c86 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -41,6 +41,7 @@
#include "BKE_paint.h"
#include "GPU_buffers.h"
+#include "GPU_immediate.h"
#include "bmesh.h"
@@ -636,7 +637,6 @@ void BKE_pbvh_free(PBVH *bvh)
BLI_gset_free(node->bm_other_verts, NULL);
}
}
- GPU_pbvh_multires_buffers_free(&bvh->grid_common_gpu_buffer);
if (bvh->deformed) {
if (bvh->verts) {
@@ -1101,7 +1101,6 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
static int pbvh_get_buffers_update_flags(PBVH *bvh)
{
int update_flags = 0;
- update_flags |= bvh->show_diffuse_color ? GPU_PBVH_BUFFERS_SHOW_DIFFUSE_COLOR : 0;
update_flags |= bvh->show_mask ? GPU_PBVH_BUFFERS_SHOW_MASK : 0;
return update_flags;
}
@@ -1117,19 +1116,21 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
switch (bvh->type) {
case PBVH_GRIDS:
node->draw_buffers =
- GPU_pbvh_grid_buffers_build(node->prim_indices,
- node->totprim,
- bvh->grid_hidden,
- bvh->gridkey.grid_size,
- &bvh->gridkey, &bvh->grid_common_gpu_buffer);
+ GPU_pbvh_grid_buffers_build(
+ node->prim_indices,
+ node->totprim,
+ bvh->grid_hidden,
+ bvh->gridkey.grid_size,
+ &bvh->gridkey);
break;
case PBVH_FACES:
node->draw_buffers =
- GPU_pbvh_mesh_buffers_build(node->face_vert_indices,
- bvh->mpoly, bvh->mloop, bvh->looptri,
- bvh->verts,
- node->prim_indices,
- node->totprim);
+ GPU_pbvh_mesh_buffers_build(
+ node->face_vert_indices,
+ bvh->mpoly, bvh->mloop, bvh->looptri,
+ bvh->verts,
+ node->prim_indices,
+ node->totprim);
break;
case PBVH_BMESH:
node->draw_buffers =
@@ -1180,19 +1181,6 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
}
}
-void BKE_pbvh_draw_BB(PBVH *bvh)
-{
- GPU_pbvh_BB_draw_init();
-
- for (int a = 0; a < bvh->totnode; a++) {
- PBVHNode *node = &bvh->nodes[a];
-
- GPU_pbvh_BB_draw(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0));
- }
-
- GPU_pbvh_BB_draw_end();
-}
-
static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag)
{
int update = 0;
@@ -1353,6 +1341,12 @@ void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key)
*key = bvh->gridkey;
}
+struct CCGElem **BKE_pbvh_get_grids(const PBVH *bvh, int *num_grids)
+{
+ BLI_assert(bvh->type == PBVH_GRIDS);
+ *num_grids = bvh->totgrid;
+ return bvh->grids;
+}
BMesh *BKE_pbvh_get_bmesh(PBVH *bvh)
{
@@ -1996,42 +1990,6 @@ bool BKE_pbvh_node_find_nearest_to_ray(
return hit;
}
-typedef struct {
- DMSetMaterial setMaterial;
- bool wireframe;
- bool fast;
-} PBVHNodeDrawData;
-
-void BKE_pbvh_node_draw(PBVHNode *node, void *data_v)
-{
- PBVHNodeDrawData *data = data_v;
-
-#if 0
- /* XXX: Just some quick code to show leaf nodes in different colors */
- float col[3];
- float spec[3] = {0.0f, 0.0f, 0.0f};
-
- if (0) { //is_partial) {
- col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6;
- }
- else {
- srand((long long)node);
- for (int i = 0; i < 3; ++i)
- col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7;
- }
-
- GPU_basic_shader_colors(col, spec, 0, 1.0f);
- glColor3f(1, 0, 0);
-#endif
-
- if (!(node->flag & PBVH_FullyHidden)) {
- GPU_pbvh_buffers_draw(node->draw_buffers,
- data->setMaterial,
- data->wireframe,
- data->fast);
- }
-}
-
typedef enum {
ISECT_INSIDE,
ISECT_OUTSIDE,
@@ -2091,37 +2049,44 @@ bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data)
return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE;
}
-static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node)
-{
- if (!node->draw_buffers)
- return;
-
- if (GPU_pbvh_buffers_diffuse_changed(node->draw_buffers, node->bm_faces, bvh->show_diffuse_color))
- node->flag |= PBVH_UpdateDrawBuffers;
-}
+struct PBVHNodeDrawCallbackData {
+ void (*draw_fn)(void *user_data, GPUBatch *batch);
+ void *user_data;
+ bool fast;
+ bool only_mask; /* Only draw nodes that have mask data. */
+};
-static void pbvh_node_check_mask_changed(PBVH *bvh, PBVHNode *node)
+static void pbvh_node_draw_cb(PBVHNode *node, void *data_v)
{
- if (!node->draw_buffers) {
- return;
- }
- if (GPU_pbvh_buffers_mask_changed(node->draw_buffers, bvh->show_mask)) {
- node->flag |= PBVH_UpdateDrawBuffers;
+ struct PBVHNodeDrawCallbackData *data = data_v;
+
+ if (!(node->flag & PBVH_FullyHidden)) {
+ GPUBatch *triangles = GPU_pbvh_buffers_batch_get(node->draw_buffers, data->fast);
+ bool show_mask = GPU_pbvh_buffers_has_mask(node->draw_buffers);
+ if (!data->only_mask || show_mask) {
+ if (triangles != NULL) {
+ data->draw_fn(data->user_data, triangles);
+ }
+ }
}
}
-void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
- DMSetMaterial setMaterial, bool wireframe, bool fast)
-{
- PBVHNodeDrawData draw_data = {setMaterial, wireframe, fast};
+/**
+ * Version of #BKE_pbvh_draw that runs a callback.
+ */
+void BKE_pbvh_draw_cb(
+ PBVH *bvh, float (*planes)[4], float (*fnors)[3], bool fast, bool only_mask,
+ void (*draw_fn)(void *user_data, GPUBatch *batch), void *user_data)
+{
+ struct PBVHNodeDrawCallbackData draw_data = {
+ .only_mask = only_mask,
+ .fast = fast,
+ .draw_fn = draw_fn,
+ .user_data = user_data,
+ };
PBVHNode **nodes;
int totnode;
- for (int a = 0; a < bvh->totnode; a++) {
- pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]);
- pbvh_node_check_mask_changed(bvh, &bvh->nodes[a]);
- }
-
BKE_pbvh_search_gather(bvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers),
&nodes, &totnode);
@@ -2131,15 +2096,19 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*fnors)[3],
if (nodes) MEM_freeN(nodes);
if (planes) {
- BKE_pbvh_search_callback(bvh, BKE_pbvh_node_planes_contain_AABB,
- planes, BKE_pbvh_node_draw, &draw_data);
+ BKE_pbvh_search_callback(
+ bvh, BKE_pbvh_node_planes_contain_AABB,
+ planes, pbvh_node_draw_cb, &draw_data);
}
else {
- BKE_pbvh_search_callback(bvh, NULL, NULL, BKE_pbvh_node_draw, &draw_data);
+ BKE_pbvh_search_callback(
+ bvh, NULL,
+ NULL, pbvh_node_draw_cb, &draw_data);
}
-
+#if 0
if (G.debug_value == 14)
- BKE_pbvh_draw_BB(bvh);
+ pbvh_draw_BB(bvh);
+#endif
}
void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces,
@@ -2195,8 +2164,13 @@ float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3]
return vertCos;
}
-void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
+void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3], const int totvert)
{
+ if (totvert != pbvh->totvert) {
+ BLI_assert(!"PBVH: Given deforming vcos number does not natch PBVH vertex number!");
+ return;
+ }
+
if (!pbvh->deformed) {
if (pbvh->verts) {
/* if pbvh is not already deformed, verts/faces points to the */
@@ -2351,24 +2325,24 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK);
}
-void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color)
+bool pbvh_has_mask(PBVH *bvh)
{
- bool has_mask = false;
-
switch (bvh->type) {
case PBVH_GRIDS:
- has_mask = (bvh->gridkey.has_mask != 0);
- break;
+ return (bvh->gridkey.has_mask != 0);
case PBVH_FACES:
- has_mask = (bvh->vdata && CustomData_get_layer(bvh->vdata,
- CD_PAINT_MASK));
- break;
+ return (bvh->vdata && CustomData_get_layer(bvh->vdata,
+ CD_PAINT_MASK));
case PBVH_BMESH:
- has_mask = (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
- break;
+ return (bvh->bm && (CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK) != -1));
}
- bvh->show_diffuse_color = !has_mask || show_diffuse_color;
+ return false;
+}
+
+void pbvh_show_diffuse_color_set(PBVH *bvh, bool show_diffuse_color)
+{
+ bvh->show_diffuse_color = !pbvh_has_mask(bvh) || show_diffuse_color;
}
void pbvh_show_mask_set(PBVH *bvh, bool show_mask)
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index e32a5d0681e..3369b05ea60 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -27,7 +27,7 @@
#include "BLI_utildefines.h"
#include "BLI_buffer.h"
#include "BLI_ghash.h"
-#include "BLI_heap.h"
+#include "BLI_heap_simple.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
@@ -721,7 +721,7 @@ static void pbvh_bmesh_node_drop_orig(PBVHNode *node)
struct EdgeQueue;
typedef struct EdgeQueue {
- Heap *heap;
+ HeapSimple *heap;
const float *center;
float center_proj[3]; /* for when we use projected coords. */
float radius_squared;
@@ -840,7 +840,7 @@ static void edge_queue_insert(
BMVert **pair = BLI_mempool_alloc(eq_ctx->pool);
pair[0] = e->v1;
pair[1] = e->v2;
- BLI_heap_insert(eq_ctx->q->heap, priority, pair);
+ BLI_heapsimple_insert(eq_ctx->q->heap, priority, pair);
#ifdef USE_EDGEQUEUE_TAG
BLI_assert(EDGE_QUEUE_TEST(e) == false);
EDGE_QUEUE_ENABLE(e);
@@ -1008,7 +1008,7 @@ static void long_edge_queue_create(
PBVH *bvh, const float center[3], const float view_normal[3],
float radius, const bool use_frontface, const bool use_projected)
{
- eq_ctx->q->heap = BLI_heap_new();
+ eq_ctx->q->heap = BLI_heapsimple_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len;
@@ -1070,7 +1070,7 @@ static void short_edge_queue_create(
PBVH *bvh, const float center[3], const float view_normal[3],
float radius, const bool use_frontface, const bool use_projected)
{
- eq_ctx->q->heap = BLI_heap_new();
+ eq_ctx->q->heap = BLI_heapsimple_new();
eq_ctx->q->center = center;
eq_ctx->q->radius_squared = radius * radius;
eq_ctx->q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
@@ -1237,8 +1237,8 @@ static bool pbvh_bmesh_subdivide_long_edges(
{
bool any_subdivided = false;
- while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
- BMVert **pair = BLI_heap_pop_min(eq_ctx->q->heap);
+ while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
+ BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
BMVert *v1 = pair[0], *v2 = pair[1];
BMEdge *e;
@@ -1454,8 +1454,8 @@ static bool pbvh_bmesh_collapse_short_edges(
/* deleted verts point to vertices they were merged into, or NULL when removed. */
GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
- while (!BLI_heap_is_empty(eq_ctx->q->heap)) {
- BMVert **pair = BLI_heap_pop_min(eq_ctx->q->heap);
+ while (!BLI_heapsimple_is_empty(eq_ctx->q->heap)) {
+ BMVert **pair = BLI_heapsimple_pop_min(eq_ctx->q->heap);
BMVert *v1 = pair[0], *v2 = pair[1];
BLI_mempool_free(eq_ctx->pool, pair);
pair = NULL;
@@ -1961,7 +1961,7 @@ bool BKE_pbvh_bmesh_update_topology(
short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_collapse_short_edges(
&eq_ctx, bvh, &deleted_faces);
- BLI_heap_free(q.heap, NULL);
+ BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
@@ -1976,7 +1976,7 @@ bool BKE_pbvh_bmesh_update_topology(
long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius, use_frontface, use_projected);
modified |= pbvh_bmesh_subdivide_long_edges(
&eq_ctx, bvh, &edge_loops);
- BLI_heap_free(q.heap, NULL);
+ BLI_heapsimple_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
}
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 4aef97bda47..ea8bd1933cd 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -144,11 +144,6 @@ struct PBVH {
const DMFlagMat *grid_flag_mats;
int totgrid;
BLI_bitmap **grid_hidden;
- /* index_buf of GPU_PBVH_Buffers can be the same for all 'fully drawn' nodes (same size).
- * Previously was stored in a static var in gpu_buffer.c, but this breaks in case we handle several different
- * objects in sculpt mode with different sizes at the same time, so now storing that common gpu buffer
- * in an opaque pointer per pbvh. See T47637. */
- struct GridCommonGPUBuffer *grid_common_gpu_buffer;
/* Only used during BVH build and update,
* don't need to remain valid after */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index f611e7a94cd..99451a7b6c1 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
+#include "DNA_collection_types.h"
#include "DNA_dynamicpaint_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -59,8 +60,10 @@
#include "BKE_appdir.h"
#include "BKE_anim.h"
#include "BKE_cloth.h"
+#include "BKE_collection.h"
#include "BKE_dynamicpaint.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -72,6 +75,8 @@
#include "BIK_api.h"
+#include "DEG_depsgraph.h"
+
#ifdef WITH_BULLET
# include "RBI_api.h"
#endif
@@ -1291,8 +1296,8 @@ static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUS
if (rbo->type == RBO_TYPE_ACTIVE) {
#ifdef WITH_BULLET
- RB_body_get_position(rbo->physics_object, rbo->pos);
- RB_body_get_orientation(rbo->physics_object, rbo->orn);
+ RB_body_get_position(rbo->shared->physics_object, rbo->pos);
+ RB_body_get_orientation(rbo->shared->physics_object, rbo->orn);
#endif
PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos);
PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn);
@@ -1385,9 +1390,9 @@ void BKE_ptcache_id_from_softbody(PTCacheID *pid, Object *ob, SoftBody *sb)
pid->ob= ob;
pid->calldata= sb;
pid->type= PTCACHE_TYPE_SOFTBODY;
- pid->cache= sb->pointcache;
- pid->cache_ptr= &sb->pointcache;
- pid->ptcaches= &sb->ptcaches;
+ pid->cache= sb->shared->pointcache;
+ pid->cache_ptr= &sb->shared->pointcache;
+ pid->ptcaches= &sb->shared->ptcaches;
pid->totpoint= pid->totwrite= ptcache_softbody_totpoint;
pid->error = ptcache_softbody_error;
@@ -1615,9 +1620,9 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->ob= ob;
pid->calldata= rbw;
pid->type= PTCACHE_TYPE_RIGIDBODY;
- pid->cache= rbw->pointcache;
- pid->cache_ptr= &rbw->pointcache;
- pid->ptcaches= &rbw->ptcaches;
+ pid->cache= rbw->shared->pointcache;
+ pid->cache_ptr= &rbw->shared->pointcache;
+ pid->ptcaches= &rbw->shared->ptcaches;
pid->totpoint= pid->totwrite= ptcache_rigidbody_totpoint;
pid->error = ptcache_rigidbody_error;
@@ -1648,7 +1653,26 @@ void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, Object *ob, RigidBodyWorld *r
pid->file_type = PTCACHE_FILE_PTCACHE;
}
-void BKE_ptcache_ids_from_object(Main *bmain, ListBase *lb, Object *ob, Scene *scene, int duplis)
+PTCacheID BKE_ptcache_id_find(Object *ob, Scene *scene, PointCache *cache)
+{
+ PTCacheID result = {0};
+
+ ListBase pidlist;
+ BKE_ptcache_ids_from_object(&pidlist, ob, scene, MAX_DUPLI_RECUR);
+
+ for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ if (pid->cache == cache) {
+ result = *pid;
+ break;
+ }
+ }
+
+ BLI_freelistN(&pidlist);
+
+ return result;
+}
+
+void BKE_ptcache_ids_from_object(ListBase *lb, Object *ob, Scene *scene, int duplis)
{
PTCacheID *pid;
ParticleSystem *psys;
@@ -1716,23 +1740,19 @@ void BKE_ptcache_ids_from_object(Main *bmain, ListBase *lb, Object *ob, Scene *s
BLI_addtail(lb, pid);
}
- if (scene && (duplis-- > 0) && (ob->transflag & OB_DUPLI)) {
- ListBase *lb_dupli_ob;
- /* don't update the dupli groups, we only want their pid's */
- if ((lb_dupli_ob = object_duplilist_ex(bmain, bmain->eval_ctx, scene, ob, false))) {
- DupliObject *dob;
- for (dob= lb_dupli_ob->first; dob; dob= dob->next) {
- if (dob->ob != ob) { /* avoids recursive loops with dupliframes: bug 22988 */
- ListBase lb_dupli_pid;
- BKE_ptcache_ids_from_object(bmain, &lb_dupli_pid, dob->ob, scene, duplis);
- BLI_movelisttolist(lb, &lb_dupli_pid);
- if (lb_dupli_pid.first)
- printf("Adding Dupli\n");
- }
+ /* Consider all object in dupli groups to be part of the same object,
+ * for baking with linking dupligroups. Once we have better overrides
+ * this can be revisited so users select the local objects directly. */
+ if (scene && (duplis-- > 0) && (ob->dup_group)) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(ob->dup_group, object)
+ {
+ if (object != ob) {
+ ListBase lb_dupli_pid;
+ BKE_ptcache_ids_from_object(&lb_dupli_pid, object, scene, duplis);
+ BLI_movelisttolist(lb, &lb_dupli_pid);
}
-
- free_object_duplilist(lb_dupli_ob); /* does restore */
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
}
@@ -3151,19 +3171,6 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra
if (startframe && endframe) {
*startframe= cache->startframe;
*endframe= cache->endframe;
-
- /* TODO: time handling with object offsets and simulated vs. cached
- * particles isn't particularly easy, so for now what you see is what
- * you get. In the future point cache could handle the whole particle
- * system timing. */
-#if 0
- if ((ob->partype & PARSLOW)==0) {
- offset= ob->sf;
-
- *startframe += (int)(offset+0.5f);
- *endframe += (int)(offset+0.5f);
- }
-#endif
}
/* verify cached_frames array is up to date */
@@ -3269,12 +3276,6 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
sbFreeSimulation(pid->calldata);
else if (pid->type == PTCACHE_TYPE_PARTICLES)
psys_reset(pid->calldata, PSYS_RESET_DEPSGRAPH);
-#if 0
- else if (pid->type == PTCACHE_TYPE_SMOKE_DOMAIN)
- smokeModifier_reset(pid->calldata);
- else if (pid->type == PTCACHE_TYPE_SMOKE_HIGHRES)
- smokeModifier_reset_turbulence(pid->calldata);
-#endif
else if (pid->type == PTCACHE_TYPE_DYNAMICPAINT)
dynamicPaint_clearSurface(scene, (DynamicPaintSurface*)pid->calldata);
}
@@ -3356,6 +3357,7 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
if (ob->type == OB_ARMATURE)
BIK_clear_cache(ob->pose);
+ DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE);
return reset;
}
@@ -3510,13 +3512,14 @@ PointCache *BKE_ptcache_copy_list(ListBase *ptcaches_new, const ListBase *ptcach
* every user action changing stuff, and then it runs a complete bake??? (ton) */
/* Baking */
-void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene)
+void BKE_ptcache_quick_cache_all(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
PTCacheBaker baker;
memset(&baker, 0, sizeof(baker));
baker.bmain = bmain;
baker.scene = scene;
+ baker.view_layer = view_layer;
baker.bake = 0;
baker.render = 0;
baker.anim_init = 0;
@@ -3542,6 +3545,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
{
Main *bmain = baker->bmain;
Scene *scene = baker->scene;
+ ViewLayer *view_layer = baker->view_layer;
+ struct Depsgraph *depsgraph = baker->depsgraph;
Scene *sce_iter; /* SETLOOPER macro only */
Base *base;
ListBase pidlist;
@@ -3571,7 +3576,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
/* get all pids from the object and search for smoke low res */
ListBase pidlist2;
PTCacheID *pid2;
- BKE_ptcache_ids_from_object(bmain, &pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
+ BKE_ptcache_ids_from_object(&pidlist2, pid->ob, scene, MAX_DUPLI_RECUR);
for (pid2=pidlist2.first; pid2; pid2=pid2->next) {
if (pid2->type == PTCACHE_TYPE_SMOKE_DOMAIN) {
if (pid2->cache && !(pid2->cache->flag & PTCACHE_BAKED)) {
@@ -3604,9 +3609,9 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
else {
- for (SETLOOPER(scene, sce_iter, base)) {
+ for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
/* cache/bake everything in the scene */
- BKE_ptcache_ids_from_object(bmain, &pidlist, base->object, scene, MAX_DUPLI_RECUR);
+ BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
for (pid=pidlist.first; pid; pid=pid->next) {
cache = pid->cache;
@@ -3660,7 +3665,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
stime = ptime = PIL_check_seconds_timer();
for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) {
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
if (baker->update_progress) {
float progress = ((float)(CFRA - startframe)/(float)(endframe - startframe));
@@ -3715,8 +3720,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
else {
- for (SETLOOPER(scene, sce_iter, base)) {
- BKE_ptcache_ids_from_object(bmain, &pidlist, base->object, scene, MAX_DUPLI_RECUR);
+ for (SETLOOPER_VIEW_LAYER(scene, view_layer, sce_iter, base)) {
+ BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
for (pid=pidlist.first; pid; pid=pid->next) {
/* skip hair particles */
@@ -3746,7 +3751,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
CFRA = cfrao;
if (bake) { /* already on cfra unless baking */
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
/* TODO: call redraw all windows somehow */
diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c
deleted file mode 100644
index cb297744ab8..00000000000
--- a/source/blender/blenkernel/intern/property.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): ton roosendaal
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/property.c
- * \ingroup bke
- *
- * This module deals with bProperty only,
- * they are used on blender objects in the game engine
- * (where they get converted into C++ classes - CValue and subclasses)
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_property_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_blenlib.h"
-
-#include "BKE_property.h"
-
-void BKE_bproperty_free(bProperty *prop)
-{
-
- if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
- MEM_freeN(prop);
-
-}
-
-void BKE_bproperty_free_list(ListBase *lb)
-{
- bProperty *prop;
-
- while ((prop = BLI_pophead(lb))) {
- BKE_bproperty_free(prop);
- }
-}
-
-bProperty *BKE_bproperty_copy(const bProperty *prop)
-{
- bProperty *propn;
-
- propn = MEM_dupallocN(prop);
- if (prop->poin && prop->poin != &prop->data) {
- propn->poin = MEM_dupallocN(prop->poin);
- }
- else {
- propn->poin = &propn->data;
- }
-
- return propn;
-}
-
-void BKE_bproperty_copy_list(ListBase *lbn, const ListBase *lbo)
-{
- bProperty *prop, *propn;
- BKE_bproperty_free_list(lbn); /* in case we are copying to an object with props */
- prop = lbo->first;
- while (prop) {
- propn = BKE_bproperty_copy(prop);
- BLI_addtail(lbn, propn);
- prop = prop->next;
- }
-
-
-}
-
-void BKE_bproperty_init(bProperty *prop)
-{
- /* also use when property changes type */
-
- if (prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
- prop->poin = NULL;
-
- prop->data = 0;
-
- switch (prop->type) {
- case GPROP_BOOL:
- case GPROP_INT:
- case GPROP_FLOAT:
- case GPROP_TIME:
- prop->poin = &prop->data;
- break;
- case GPROP_STRING:
- prop->poin = MEM_callocN(MAX_PROPSTRING, "property string");
- break;
- }
-}
-
-
-bProperty *BKE_bproperty_new(int type)
-{
- bProperty *prop;
-
- prop = MEM_callocN(sizeof(bProperty), "property");
- prop->type = type;
-
- BKE_bproperty_init(prop);
-
- strcpy(prop->name, "prop");
-
- return prop;
-}
-
-
-bProperty *BKE_bproperty_object_get(Object *ob, const char *name)
-{
- return BLI_findstring(&ob->prop, name, offsetof(bProperty, name));
-}
-
-void BKE_bproperty_object_set(Object *ob, bProperty *propc)
-{
- bProperty *prop;
- prop = BKE_bproperty_object_get(ob, propc->name);
- if (prop) {
- BLI_remlink(&ob->prop, prop);
- BKE_bproperty_free(prop);
- }
- BLI_addtail(&ob->prop, BKE_bproperty_copy(propc));
-}
-
-/* negative: prop is smaller
- * positive: prop is larger
- */
-#if 0 /* UNUSED */
-int BKE_bproperty_cmp(bProperty *prop, const char *str)
-{
-// extern int Gdfra; /* sector.c */
- float fvalue, ftest;
-
- switch (prop->type) {
- case GPROP_BOOL:
- if (BLI_strcasecmp(str, "true") == 0) {
- if (prop->data == 1) return 0;
- else return 1;
- }
- else if (BLI_strcasecmp(str, "false") == 0) {
- if (prop->data == 0) return 0;
- else return 1;
- }
- /* no break, do GPROP_int too! */
-
- case GPROP_INT:
- return prop->data - atoi(str);
-
- case GPROP_FLOAT:
- case GPROP_TIME:
- /* WARNING: untested for GPROP_TIME
- * function isn't used currently */
- fvalue = *((float *)&prop->data);
- ftest = (float)atof(str);
- if (fvalue > ftest) return 1;
- else if (fvalue < ftest) return -1;
- return 0;
-
- case GPROP_STRING:
- return strcmp(prop->poin, str);
- }
-
- return 0;
-}
-#endif
-
-void BKE_bproperty_set(bProperty *prop, const char *str)
-{
-// extern int Gdfra; /* sector.c */
-
- switch (prop->type) {
- case GPROP_BOOL:
- if (BLI_strcasecmp(str, "true") == 0) prop->data = 1;
- else if (BLI_strcasecmp(str, "false") == 0) prop->data = 0;
- else prop->data = (atoi(str) != 0);
- break;
- case GPROP_INT:
- prop->data = atoi(str);
- break;
- case GPROP_FLOAT:
- case GPROP_TIME:
- *((float *)&prop->data) = (float)atof(str);
- break;
- case GPROP_STRING:
- strcpy(prop->poin, str); /* TODO - check size? */
- break;
- }
-
-}
-
-void BKE_bproperty_add(bProperty *prop, const char *str)
-{
-// extern int Gdfra; /* sector.c */
-
- switch (prop->type) {
- case GPROP_BOOL:
- case GPROP_INT:
- prop->data += atoi(str);
- break;
- case GPROP_FLOAT:
- case GPROP_TIME:
- *((float *)&prop->data) += (float)atof(str);
- break;
- case GPROP_STRING:
- /* strcpy(prop->poin, str); */
- break;
- }
-}
-
-/* reads value of property, sets it in chars in str */
-void BKE_bproperty_set_valstr(bProperty *prop, char str[MAX_PROPSTRING])
-{
-// extern int Gdfra; /* sector.c */
-
- if (str == NULL) return;
-
- switch (prop->type) {
- case GPROP_BOOL:
- case GPROP_INT:
- sprintf(str, "%d", prop->data);
- break;
- case GPROP_FLOAT:
- case GPROP_TIME:
- sprintf(str, "%f", *((float *)&prop->data));
- break;
- case GPROP_STRING:
- BLI_strncpy(str, prop->poin, MAX_PROPSTRING);
- break;
- }
-}
-
-#if 0 /* UNUSED */
-void cp_property(bProperty *prop1, bProperty *prop2)
-{
- char str[128];
-
- BKE_bproperty_set_valstr(prop2, str);
-
- BKE_bproperty_set(prop1, str);
-}
-#endif
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index bfc61794935..68bc6c407ac 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -47,34 +47,39 @@
#endif
#include "DNA_ID.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
-#include "BKE_cdderivedmesh.h"
-#include "BKE_depsgraph.h"
+#include "BKE_collection.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
/* ************************************** */
/* Memory Management */
/* Freeing Methods --------------------- */
-#ifndef WITH_BULLET
+#ifdef WITH_BULLET
+static void rigidbody_update_ob_array(RigidBodyWorld *rbw);
+#else
static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) {}
static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) {}
static void RB_dworld_delete(void *UNUSED(world)) {}
@@ -85,44 +90,51 @@ static void RB_constraint_delete(void *UNUSED(con)) {}
#endif
/* Free rigidbody world */
-void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
+void BKE_rigidbody_free_world(Scene *scene)
{
+ bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ scene->rigidbody_world = NULL;
+
/* sanity check */
if (!rbw)
return;
- if (rbw->physics_world) {
+ if (is_orig && rbw->shared->physics_world) {
/* free physics references, we assume that all physics objects in will have been added to the world */
- GroupObject *go;
if (rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- if (go->ob && go->ob->rigidbody_constraint) {
- RigidBodyCon *rbc = go->ob->rigidbody_constraint;
-
- if (rbc->physics_constraint)
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object)
+ {
+ if (object->rigidbody_constraint) {
+ RigidBodyCon *rbc = object->rigidbody_constraint;
+ if (rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ }
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
- if (rbw->group) {
- for (go = rbw->group->gobject.first; go; go = go->next) {
- if (go->ob && go->ob->rigidbody_object) {
- RigidBodyOb *rbo = go->ob->rigidbody_object;
- if (rbo->physics_object)
- RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
- }
+ if (rbw->group) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ BKE_rigidbody_free_object(object, rbw);
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
/* free dynamics world */
- RB_dworld_delete(rbw->physics_world);
+ RB_dworld_delete(rbw->shared->physics_world);
}
if (rbw->objects)
free(rbw->objects);
- /* free cache */
- BKE_ptcache_free_list(&(rbw->ptcaches));
- rbw->pointcache = NULL;
+ if (is_orig) {
+ /* free cache */
+ BKE_ptcache_free_list(&(rbw->shared->ptcaches));
+ rbw->shared->pointcache = NULL;
+
+ MEM_freeN(rbw->shared);
+ }
/* free effector weights */
if (rbw->effector_weights)
@@ -133,8 +145,9 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
}
/* Free RigidBody settings and sim instances */
-void BKE_rigidbody_free_object(Object *ob)
+void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw)
{
+ bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0;
RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL;
/* sanity check */
@@ -142,14 +155,26 @@ void BKE_rigidbody_free_object(Object *ob)
return;
/* free physics references */
- if (rbo->physics_object) {
- RB_body_delete(rbo->physics_object);
- rbo->physics_object = NULL;
- }
+ if (is_orig) {
+ if (rbo->shared->physics_object) {
+ BLI_assert(rbw);
+ if (rbw) {
+ /* We can only remove the body from the world if the world is known.
+ * The world is generally only unknown if it's an evaluated copy of
+ * an object that's being freed, in which case this code isn't run anyway. */
+ RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object);
+ }
- if (rbo->physics_shape) {
- RB_shape_delete(rbo->physics_shape);
- rbo->physics_shape = NULL;
+ RB_body_delete(rbo->shared->physics_object);
+ rbo->shared->physics_object = NULL;
+ }
+
+ if (rbo->shared->physics_shape) {
+ RB_shape_delete(rbo->shared->physics_shape);
+ rbo->shared->physics_shape = NULL;
+ }
+
+ MEM_freeN(rbo->shared);
}
/* free data itself */
@@ -186,7 +211,7 @@ void BKE_rigidbody_free_constraint(Object *ob)
* be added to relevant groups later...
*/
-RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int UNUSED(flag))
+RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag)
{
RigidBodyOb *rboN = NULL;
@@ -194,12 +219,13 @@ RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int UNUSED(flag))
/* just duplicate the whole struct first (to catch all the settings) */
rboN = MEM_dupallocN(ob->rigidbody_object);
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ /* This is a regular copy, and not a CoW copy for depsgraph evaluation */
+ rboN->shared = MEM_callocN(sizeof(*rboN->shared), "RigidBodyOb_Shared");
+ }
+
/* tag object as needing to be verified */
rboN->flag |= RBO_FLAG_NEEDS_VALIDATE;
-
- /* clear out all the fields which need to be revalidated later */
- rboN->physics_object = NULL;
- rboN->physics_shape = NULL;
}
/* return new copy of settings */
@@ -228,32 +254,39 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(f
/* ************************************** */
/* Setup Utilities - Validate Sim Instances */
-/* get the appropriate DerivedMesh based on rigid body mesh source */
-static DerivedMesh *rigidbody_get_mesh(Object *ob)
+/* get the appropriate evaluated mesh based on rigid body mesh source */
+static Mesh *rigidbody_get_mesh(Object *ob)
{
- if (ob->rigidbody_object->mesh_source == RBO_MESH_DEFORM) {
- return ob->derivedDeform;
- }
- else if (ob->rigidbody_object->mesh_source == RBO_MESH_FINAL) {
- return ob->derivedFinal;
- }
- else {
- return CDDM_from_mesh(ob->data);
- }
+ switch (ob->rigidbody_object->mesh_source) {
+ case RBO_MESH_DEFORM:
+ return ob->runtime.mesh_deform_eval;
+ case RBO_MESH_FINAL:
+ return ob->runtime.mesh_eval;
+ case RBO_MESH_BASE:
+ /* This mesh may be used for computing looptris, which should be done
+ * on the original; otherwise every time the CoW is recreated it will
+ * have to be recomputed. */
+ BLI_assert(ob->rigidbody_object->mesh_source == RBO_MESH_BASE);
+ return ob->runtime.mesh_orig;
+ }
+
+ /* Just return something sensible so that at least Blender won't crash. */
+ BLI_assert(!"Unknown mesh source");
+ return ob->runtime.mesh_eval;
}
/* create collision shape of mesh - convex hull */
static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, float margin, bool *can_embed)
{
rbCollisionShape *shape = NULL;
- DerivedMesh *dm = NULL;
+ Mesh *mesh = NULL;
MVert *mvert = NULL;
int totvert = 0;
if (ob->type == OB_MESH && ob->data) {
- dm = rigidbody_get_mesh(ob);
- mvert = (dm) ? dm->getVertArray(dm) : NULL;
- totvert = (dm) ? dm->getNumVerts(dm) : 0;
+ mesh = rigidbody_get_mesh(ob);
+ mvert = (mesh) ? mesh->mvert : NULL;
+ totvert = (mesh) ? mesh->totvert : 0;
}
else {
printf("ERROR: cannot make Convex Hull collision shape for non-Mesh object\n");
@@ -266,9 +299,6 @@ static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, fl
printf("ERROR: no vertices to define Convex Hull collision shape with\n");
}
- if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE)
- dm->release(dm);
-
return shape;
}
@@ -280,24 +310,24 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
rbCollisionShape *shape = NULL;
if (ob->type == OB_MESH) {
- DerivedMesh *dm = NULL;
+ Mesh *mesh = NULL;
MVert *mvert;
const MLoopTri *looptri;
int totvert;
int tottri;
const MLoop *mloop;
- dm = rigidbody_get_mesh(ob);
+ mesh = rigidbody_get_mesh(ob);
/* ensure mesh validity, then grab data */
- if (dm == NULL)
+ if (mesh == NULL)
return NULL;
- mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
- looptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
- mloop = dm->getLoopArray(dm);
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
/* sanity checking - potential case when no data will be present */
if ((totvert == 0) || (tottri == 0)) {
@@ -347,11 +377,6 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
shape = RB_shape_new_gimpact_mesh(mdata);
}
}
-
- /* cleanup temp data */
- if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
- dm->release(dm);
- }
}
else {
printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n");
@@ -381,7 +406,7 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
return;
/* don't create a new shape if we already have one and don't want to rebuild it */
- if (rbo->physics_shape && !rebuild)
+ if (rbo->shared->physics_shape && !rebuild)
return;
/* if automatically determining dimensions, use the Object's boundbox
@@ -445,15 +470,16 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
break;
}
/* use box shape if we can't fall back to old shape */
- if (new_shape == NULL && rbo->physics_shape == NULL) {
+ if (new_shape == NULL && rbo->shared->physics_shape == NULL) {
new_shape = RB_shape_new_box(size[0], size[1], size[2]);
}
/* assign new collision shape if creation was successful */
if (new_shape) {
- if (rbo->physics_shape)
- RB_shape_delete(rbo->physics_shape);
- rbo->physics_shape = new_shape;
- RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo));
+ if (rbo->shared->physics_shape) {
+ RB_shape_delete(rbo->shared->physics_shape);
+ }
+ rbo->shared->physics_shape = new_shape;
+ RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo));
}
}
@@ -514,30 +540,25 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
case RB_SHAPE_TRIMESH:
{
if (ob->type == OB_MESH) {
- DerivedMesh *dm = rigidbody_get_mesh(ob);
+ Mesh *mesh = rigidbody_get_mesh(ob);
MVert *mvert;
const MLoopTri *lt = NULL;
int totvert, tottri = 0;
const MLoop *mloop = NULL;
/* ensure mesh validity, then grab data */
- if (dm == NULL)
+ if (mesh == NULL)
return;
- mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
- lt = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
- mloop = dm->getLoopArray(dm);
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ lt = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
if (totvert > 0 && tottri > 0) {
BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL);
}
-
- /* cleanup temp data */
- if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
- dm->release(dm);
- }
}
else {
/* rough estimate from boundbox as fallback */
@@ -546,12 +567,6 @@ void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
}
break;
}
-
-#if 0 // XXX: not defined yet
- case RB_SHAPE_COMPOUND:
- volume = 0.0f;
- break;
-#endif
}
/* return the volume calculated */
@@ -597,39 +612,28 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3])
case RB_SHAPE_TRIMESH:
{
if (ob->type == OB_MESH) {
- DerivedMesh *dm = rigidbody_get_mesh(ob);
+ Mesh *mesh = rigidbody_get_mesh(ob);
MVert *mvert;
const MLoopTri *looptri;
int totvert, tottri;
const MLoop *mloop;
/* ensure mesh validity, then grab data */
- if (dm == NULL)
+ if (mesh == NULL)
return;
- mvert = dm->getVertArray(dm);
- totvert = dm->getNumVerts(dm);
- looptri = dm->getLoopTriArray(dm);
- tottri = dm->getNumLoopTri(dm);
- mloop = dm->getLoopArray(dm);
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+ looptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ tottri = mesh->runtime.looptris.len;
+ mloop = mesh->mloop;
if (totvert > 0 && tottri > 0) {
BKE_mesh_calc_volume(mvert, totvert, looptri, tottri, mloop, NULL, r_center);
}
-
- /* cleanup temp data */
- if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
- dm->release(dm);
- }
}
break;
}
-
-#if 0 // XXX: not defined yet
- case RB_SHAPE_COMPOUND:
- volume = 0.0f;
- break;
-#endif
}
}
@@ -654,48 +658,48 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
/* make sure collision shape exists */
/* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */
- if (rbo->physics_shape == NULL || rebuild)
+ if (rbo->shared->physics_shape == NULL || rebuild)
rigidbody_validate_sim_shape(ob, true);
- if (rbo->physics_object && rebuild == false) {
- RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
+ if (rbo->shared->physics_object) {
+ RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object);
}
- if (!rbo->physics_object || rebuild) {
+ if (!rbo->shared->physics_object || rebuild) {
/* remove rigid body if it already exists before creating a new one */
- if (rbo->physics_object) {
- RB_body_delete(rbo->physics_object);
+ if (rbo->shared->physics_object) {
+ RB_body_delete(rbo->shared->physics_object);
}
mat4_to_loc_quat(loc, rot, ob->obmat);
- rbo->physics_object = RB_body_new(rbo->physics_shape, loc, rot);
+ rbo->shared->physics_object = RB_body_new(rbo->shared->physics_shape, loc, rot);
- RB_body_set_friction(rbo->physics_object, rbo->friction);
- RB_body_set_restitution(rbo->physics_object, rbo->restitution);
+ RB_body_set_friction(rbo->shared->physics_object, rbo->friction);
+ RB_body_set_restitution(rbo->shared->physics_object, rbo->restitution);
- RB_body_set_damping(rbo->physics_object, rbo->lin_damping, rbo->ang_damping);
- RB_body_set_sleep_thresh(rbo->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh);
- RB_body_set_activation_state(rbo->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION);
+ RB_body_set_damping(rbo->shared->physics_object, rbo->lin_damping, rbo->ang_damping);
+ RB_body_set_sleep_thresh(rbo->shared->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh);
+ RB_body_set_activation_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION);
if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED)
- RB_body_deactivate(rbo->physics_object);
+ RB_body_deactivate(rbo->shared->physics_object);
- RB_body_set_linear_factor(rbo->physics_object,
+ RB_body_set_linear_factor(rbo->shared->physics_object,
(ob->protectflag & OB_LOCK_LOCX) == 0,
(ob->protectflag & OB_LOCK_LOCY) == 0,
(ob->protectflag & OB_LOCK_LOCZ) == 0);
- RB_body_set_angular_factor(rbo->physics_object,
+ RB_body_set_angular_factor(rbo->shared->physics_object,
(ob->protectflag & OB_LOCK_ROTX) == 0,
(ob->protectflag & OB_LOCK_ROTY) == 0,
(ob->protectflag & OB_LOCK_ROTZ) == 0);
- RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
- RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
+ RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
+ RB_body_set_kinematic_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
}
- if (rbw && rbw->physics_world)
- RB_dworld_add_body(rbw->physics_world, rbo->physics_object, rbo->col_groups);
+ if (rbw && rbw->shared->physics_world)
+ RB_dworld_add_body(rbw->shared->physics_world, rbo->shared->physics_object, rbo->col_groups);
}
/* --------------------- */
@@ -729,7 +733,8 @@ static void rigidbody_constraint_init_spring(
set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z);
}
-static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float))
+static void rigidbody_constraint_set_limits(
+ RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float))
{
if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
@@ -787,7 +792,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
if (ELEM(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) {
if (rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
RB_constraint_delete(rbc->physics_constraint);
rbc->physics_constraint = NULL;
}
@@ -795,11 +800,11 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
}
if (rbc->physics_constraint && rebuild == false) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
}
if (rbc->physics_constraint == NULL || rebuild) {
- rbRigidBody *rb1 = rbc->ob1->rigidbody_object->physics_object;
- rbRigidBody *rb2 = rbc->ob2->rigidbody_object->physics_object;
+ rbRigidBody *rb1 = rbc->ob1->rigidbody_object->shared->physics_object;
+ rbRigidBody *rb2 = rbc->ob2->rigidbody_object->shared->physics_object;
/* remove constraint if it already exists before creating a new one */
if (rbc->physics_constraint) {
@@ -903,8 +908,8 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
RB_constraint_set_solver_iterations(rbc->physics_constraint, -1);
}
- if (rbw && rbw->physics_world && rbc->physics_constraint) {
- RB_dworld_add_constraint(rbw->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS);
+ if (rbw && rbw->shared->physics_world && rbc->physics_constraint) {
+ RB_dworld_add_constraint(rbw->shared->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS);
}
}
@@ -919,14 +924,14 @@ void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool re
return;
/* create new sim world */
- if (rebuild || rbw->physics_world == NULL) {
- if (rbw->physics_world)
- RB_dworld_delete(rbw->physics_world);
- rbw->physics_world = RB_dworld_new(scene->physics_settings.gravity);
+ if (rebuild || rbw->shared->physics_world == NULL) {
+ if (rbw->shared->physics_world)
+ RB_dworld_delete(rbw->shared->physics_world);
+ rbw->shared->physics_world = RB_dworld_new(scene->physics_settings.gravity);
}
- RB_dworld_set_solver_iterations(rbw->physics_world, rbw->num_solver_iterations);
- RB_dworld_set_split_impulse(rbw->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE);
+ RB_dworld_set_solver_iterations(rbw->shared->physics_world, rbw->num_solver_iterations);
+ RB_dworld_set_split_impulse(rbw->shared->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE);
}
/* ************************************** */
@@ -947,6 +952,7 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
/* create a new sim world */
rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld");
+ rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared");
/* set default settings */
rbw->effector_weights = BKE_add_effector_weights(NULL);
@@ -958,8 +964,8 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
rbw->steps_per_second = 60; /* Bullet default (60 Hz) */
rbw->num_solver_iterations = 10; /* 10 is bullet default */
- rbw->pointcache = BKE_ptcache_add(&(rbw->ptcaches));
- rbw->pointcache->step = 1;
+ rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches));
+ rbw->shared->pointcache->step = 1;
/* return this sim world */
return rbw;
@@ -977,12 +983,16 @@ RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag)
id_us_plus((ID *)rbw_copy->constraints);
}
- /* XXX Never copy caches here? */
- rbw_copy->pointcache = BKE_ptcache_copy_list(&rbw_copy->ptcaches, &rbw->ptcaches, flag & ~LIB_ID_COPY_CACHES);
+ if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) {
+ /* This is a regular copy, and not a CoW copy for depsgraph evaluation */
+ rbw_copy->shared = MEM_callocN(sizeof(*rbw_copy->shared), "RigidBodyWorld_Shared");
+ BKE_ptcache_copy_list(&rbw_copy->shared->ptcaches, &rbw->shared->ptcaches, LIB_ID_COPY_CACHES);
+ rbw_copy->shared->pointcache = rbw_copy->shared->ptcaches.first;
+ }
rbw_copy->objects = NULL;
- rbw_copy->physics_world = NULL;
rbw_copy->numbodies = 0;
+ rigidbody_update_ob_array(rbw_copy);
return rbw_copy;
}
@@ -1024,6 +1034,7 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
/* create new settings data, and link it up */
rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb");
+ rbo->shared = MEM_callocN(sizeof(*rbo->shared), "RigidBodyOb_Shared");
/* set default settings */
rbo->type = type;
@@ -1038,8 +1049,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */
rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */
- rbo->lin_damping = 0.04f; /* 0.04 is game engine default */
- rbo->ang_damping = 0.1f; /* 0.1 is game engine default */
+ rbo->lin_damping = 0.04f;
+ rbo->ang_damping = 0.1f;
rbo->col_groups = 1;
@@ -1148,18 +1159,13 @@ RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
return scene->rigidbody_world;
}
-void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
+void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
- RigidBodyOb *rbo = ob->rigidbody_object;
RigidBodyCon *rbc;
- GroupObject *go;
int i;
if (rbw) {
- /* remove from rigidbody world, free object won't do this */
- if (rbw->physics_world && rbo->physics_object)
- RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
/* remove object from array */
if (rbw && rbw->objects) {
@@ -1173,8 +1179,8 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
/* remove object from rigid body constraints */
if (rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *obt = go->ob;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, obt)
+ {
if (obt && obt->rigidbody_constraint) {
rbc = obt->rigidbody_constraint;
if (ELEM(ob, rbc->ob1, rbc->ob2)) {
@@ -1182,11 +1188,13 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
}
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
+ BKE_collection_object_remove(bmain, rbw->group, ob, false);
}
/* remove object's settings */
- BKE_rigidbody_free_object(ob);
+ BKE_rigidbody_free_object(ob, rbw);
/* flag cache as outdated */
BKE_rigidbody_cache_reset(rbw);
@@ -1198,8 +1206,8 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
RigidBodyCon *rbc = ob->rigidbody_constraint;
/* remove from rigidbody world, free object won't do this */
- if (rbw && rbw->physics_world && rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ if (rbw && rbw->shared->physics_world && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
}
/* remove object's settings */
BKE_rigidbody_free_constraint(ob);
@@ -1215,20 +1223,32 @@ void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
/* Update object array and rigid body count so they're in sync with the rigid body group */
static void rigidbody_update_ob_array(RigidBodyWorld *rbw)
{
- GroupObject *go;
- int i, n;
+ if (rbw->group == NULL) {
+ rbw->numbodies = 0;
+ rbw->objects = realloc(rbw->objects, 0);
+ return;
+ }
- n = BLI_listbase_count(&rbw->group->gobject);
+ int n = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ (void)object;
+ n++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
if (rbw->numbodies != n) {
rbw->numbodies = n;
rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies);
}
- for (go = rbw->group->gobject.first, i = 0; go; go = go->next, i++) {
- Object *ob = go->ob;
- rbw->objects[i] = ob;
+ int i = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ rbw->objects[i] = object;
+ i++;
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
@@ -1245,51 +1265,51 @@ static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
}
/* update gravity, since this RNA setting is not part of RigidBody settings */
- RB_dworld_set_gravity(rbw->physics_world, adj_gravity);
+ RB_dworld_set_gravity(rbw->shared->physics_world, adj_gravity);
/* update object array in case there are changes */
rigidbody_update_ob_array(rbw);
}
-static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
+static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
{
float loc[3];
float rot[4];
float scale[3];
/* only update if rigid body exists */
- if (rbo->physics_object == NULL)
+ if (rbo->shared->physics_object == NULL)
return;
if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
- DerivedMesh *dm = ob->derivedDeform;
- if (dm) {
- MVert *mvert = dm->getVertArray(dm);
- int totvert = dm->getNumVerts(dm);
+ Mesh *mesh = ob->runtime.mesh_deform_eval;
+ if (mesh) {
+ MVert *mvert = mesh->mvert;
+ int totvert = mesh->totvert;
BoundBox *bb = BKE_object_boundbox_get(ob);
- RB_shape_trimesh_update(rbo->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
+ RB_shape_trimesh_update(rbo->shared->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
}
}
mat4_decompose(loc, rot, scale, ob->obmat);
/* update scale for all objects */
- RB_body_set_scale(rbo->physics_object, scale);
+ RB_body_set_scale(rbo->shared->physics_object, scale);
/* compensate for embedded convex hull collision margin */
if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH)
- RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2]));
+ RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2]));
/* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */
if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) {
- RB_body_set_kinematic_state(rbo->physics_object, true);
- RB_body_set_mass(rbo->physics_object, 0.0f);
+ RB_body_set_kinematic_state(rbo->shared->physics_object, true);
+ RB_body_set_mass(rbo->shared->physics_object, 0.0f);
}
/* update rigid body location and rotation for kinematic bodies */
if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) {
- RB_body_activate(rbo->physics_object);
- RB_body_set_loc_rot(rbo->physics_object, loc, rot);
+ RB_body_activate(rbo->shared->physics_object);
+ RB_body_set_loc_rot(rbo->shared->physics_object, loc, rot);
}
/* update influence of effectors - but don't do it on an effector */
/* only dynamic bodies need effector update */
@@ -1299,34 +1319,34 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
ListBase *effectors;
/* get effectors present in the group specified by effector_weights */
- effectors = pdInitEffectors(scene, ob, NULL, effector_weights, true);
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights);
if (effectors) {
float eff_force[3] = {0.0f, 0.0f, 0.0f};
float eff_loc[3], eff_vel[3];
/* create dummy 'point' which represents last known position of object as result of sim */
// XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals?
- RB_body_get_position(rbo->physics_object, eff_loc);
- RB_body_get_linear_velocity(rbo->physics_object, eff_vel);
+ RB_body_get_position(rbo->shared->physics_object, eff_loc);
+ RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
/* calculate net force of effectors, and apply to sim object
* - we use 'central force' since apply force requires a "relative position" which we don't have...
*/
- pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
+ BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
if (G.f & G_DEBUG)
printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2);
/* activate object in case it is deactivated */
if (!is_zero_v3(eff_force))
- RB_body_activate(rbo->physics_object);
- RB_body_apply_central_force(rbo->physics_object, eff_force);
+ RB_body_activate(rbo->shared->physics_object);
+ RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
}
else if (G.f & G_DEBUG)
printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
/* cleanup */
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
}
/* NOTE: passive objects don't need to be updated since they don't move */
@@ -1340,10 +1360,8 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
*
* \param rebuild Rebuild entire simulation
*/
-static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
+static void rigidbody_update_simulation(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
- GroupObject *go;
-
/* update world */
if (rebuild)
BKE_rigidbody_validate_sim_world(scene, rbw, true);
@@ -1356,28 +1374,26 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
* Memory management needs redesign here, this is just a dirty workaround.
*/
if (rebuild && rbw->constraints) {
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
- if (ob) {
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- if (rbc && rbc->physics_constraint) {
- RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
- RB_constraint_delete(rbc->physics_constraint);
- rbc->physics_constraint = NULL;
- }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob)
+ {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint);
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
/* update objects */
- for (go = rbw->group->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
-
- if (ob && ob->type == OB_MESH) {
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob)
+ {
+ if (ob->type == OB_MESH) {
/* validate that we've got valid object set up here... */
RigidBodyOb *rbo = ob->rigidbody_object;
/* update transformation matrix of the object so we don't get a frame of lag for simple animations */
- BKE_object_where_is_calc(scene, ob);
+ BKE_object_where_is_calc(depsgraph, scene, ob);
if (rbo == NULL) {
/* Since this object is included in the sim group but doesn't have
@@ -1394,6 +1410,9 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
/* refresh object... */
if (rebuild) {
/* World has been rebuilt so rebuild object */
+ /* TODO(Sybren): rigidbody_validate_sim_object() can call rigidbody_validate_sim_shape(),
+ * but neither resets the RBO_FLAG_NEEDS_RESHAPE flag nor calls RB_body_set_collision_shape().
+ * This results in the collision shape being created twice, which is unnecessary. */
rigidbody_validate_sim_object(rbw, ob, true);
}
else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) {
@@ -1405,76 +1424,75 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
rigidbody_validate_sim_shape(ob, true);
/* now tell RB sim about it */
// XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies
- RB_body_set_collision_shape(rbo->physics_object, rbo->physics_shape);
+ RB_body_set_collision_shape(rbo->shared->physics_object, rbo->shared->physics_shape);
}
rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
}
/* update simulation object... */
- rigidbody_update_sim_ob(scene, rbw, ob, rbo);
+ rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo);
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
/* update constraints */
if (rbw->constraints == NULL) /* no constraints, move on */
return;
- for (go = rbw->constraints->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
- if (ob) {
- /* validate that we've got valid object set up here... */
- RigidBodyCon *rbc = ob->rigidbody_constraint;
- /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
- BKE_object_where_is_calc(scene, ob);
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob)
+ {
+ /* validate that we've got valid object set up here... */
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
+ BKE_object_where_is_calc(depsgraph, scene, ob);
- if (rbc == NULL) {
- /* Since this object is included in the group but doesn't have
- * constraint settings (perhaps it was added manually), add!
- */
- ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
- rigidbody_validate_sim_constraint(rbw, ob, true);
+ if (rbc == NULL) {
+ /* Since this object is included in the group but doesn't have
+ * constraint settings (perhaps it was added manually), add!
+ */
+ ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
+ rigidbody_validate_sim_constraint(rbw, ob, true);
- rbc = ob->rigidbody_constraint;
+ rbc = ob->rigidbody_constraint;
+ }
+ else {
+ /* perform simulation data updates as tagged */
+ if (rebuild) {
+ /* World has been rebuilt so rebuild constraint */
+ rigidbody_validate_sim_constraint(rbw, ob, true);
}
- else {
- /* perform simulation data updates as tagged */
- if (rebuild) {
- /* World has been rebuilt so rebuild constraint */
- rigidbody_validate_sim_constraint(rbw, ob, true);
- }
- else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
- rigidbody_validate_sim_constraint(rbw, ob, false);
- }
- rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
+ else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
+ rigidbody_validate_sim_constraint(rbw, ob, false);
}
+ rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
-static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw)
+static void rigidbody_update_simulation_post_step(Depsgraph *depsgraph, RigidBodyWorld *rbw)
{
- GroupObject *go;
-
- for (go = rbw->group->gobject.first; go; go = go->next) {
- Object *ob = go->ob;
-
- if (ob) {
- RigidBodyOb *rbo = ob->rigidbody_object;
- /* reset kinematic state for transformed objects */
- if (rbo && (ob->flag & SELECT) && (G.moving & G_TRANSFORM_OBJ)) {
- RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
- RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
- /* deactivate passive objects so they don't interfere with deactivation of active objects */
- if (rbo->type == RBO_TYPE_PASSIVE)
- RB_body_deactivate(rbo->physics_object);
- }
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob)
+ {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ /* Reset kinematic state for transformed objects. */
+ if (rbo && base && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) {
+ RB_body_set_kinematic_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
+ RB_body_set_mass(rbo->shared->physics_object, RBO_GET_MASS(rbo));
+ /* Deactivate passive objects so they don't interfere with deactivation of active objects. */
+ if (rbo->type == RBO_TYPE_PASSIVE)
+ RB_body_deactivate(rbo->shared->physics_object);
}
}
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime)
{
- return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->pointcache->startframe);
+ return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe);
}
/* Sync rigid body and object transformations */
@@ -1564,11 +1582,11 @@ void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], flo
copy_qt_qt(ob->quat, quat);
}
- if (rbo->physics_object) {
+ if (rbo->shared->physics_object) {
/* allow passive objects to return to original transform */
if (rbo->type == RBO_TYPE_PASSIVE)
- RB_body_set_kinematic_state(rbo->physics_object, true);
- RB_body_set_loc_rot(rbo->physics_object, rbo->pos, rbo->orn);
+ RB_body_set_kinematic_state(rbo->shared->physics_object, true);
+ RB_body_set_loc_rot(rbo->shared->physics_object, rbo->pos, rbo->orn);
}
// RB_TODO update rigid body physics object's loc/rot for dynamic objects here as well (needs to be done outside bullet's update loop)
}
@@ -1576,7 +1594,7 @@ void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], flo
void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
{
if (rbw) {
- rbw->pointcache->flag |= PTCACHE_OUTDATED;
+ rbw->shared->pointcache->flag |= PTCACHE_OUTDATED;
}
}
@@ -1584,7 +1602,7 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
/* Rebuild rigid body world */
/* NOTE: this needs to be called before frame update to work correctly */
-void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
+void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
PointCache *cache;
@@ -1593,17 +1611,25 @@ void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
- cache = rbw->pointcache;
+ cache = rbw->shared->pointcache;
/* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */
- if (rbw->physics_world == NULL || rbw->numbodies != BLI_listbase_count(&rbw->group->gobject)) {
+ int n = 0;
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object)
+ {
+ (void)object;
+ n++;
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+
+ if (rbw->shared->physics_world == NULL || rbw->numbodies != n) {
cache->flag |= PTCACHE_OUTDATED;
}
if (ctime == startframe + 1 && rbw->ltime == startframe) {
if (cache->flag & PTCACHE_OUTDATED) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- rigidbody_update_simulation(scene, rbw, true);
+ rigidbody_update_simulation(depsgraph, scene, rbw, true);
BKE_ptcache_validate(cache, (int)ctime);
cache->last_exact = 0;
cache->flag &= ~PTCACHE_REDO_NEEDED;
@@ -1612,7 +1638,7 @@ void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
}
/* Run RigidBody simulation for the specified physics world */
-void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
+void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime)
{
float timestep;
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -1622,7 +1648,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
- cache = rbw->pointcache;
+ cache = rbw->shared->pointcache;
if (ctime <= startframe) {
rbw->ltime = startframe;
@@ -1634,7 +1660,7 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
}
/* don't try to run the simulation if we don't have a world yet but allow reading baked cache */
- if (rbw->physics_world == NULL && !(cache->flag & PTCACHE_BAKED))
+ if (rbw->shared->physics_world == NULL && !(cache->flag & PTCACHE_BAKED))
return;
else if (rbw->objects == NULL)
rigidbody_update_ob_array(rbw);
@@ -1649,22 +1675,28 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
return;
}
+ if (!DEG_is_active(depsgraph)) {
+ /* When the depsgraph is inactive we should neither write to the cache
+ * nor run the simulation. */
+ return;
+ }
+
/* advance simulation, we can only step one frame forward */
- if (can_simulate) {
+ if (compare_ff_relative(ctime, rbw->ltime + 1, FLT_EPSILON, 64)) {
/* write cache for first frame when on second frame */
if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) {
BKE_ptcache_write(&pid, startframe);
}
/* update and validate simulation */
- rigidbody_update_simulation(scene, rbw, false);
+ rigidbody_update_simulation(depsgraph, scene, rbw, false);
/* calculate how much time elapsed since last step in seconds */
timestep = 1.0f / (float)FPS * (ctime - rbw->ltime) * rbw->time_scale;
/* step simulation by the requested timestep, steps per second are adjusted to take time scale into account */
- RB_dworld_step_simulation(rbw->physics_world, timestep, INT_MAX, 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f));
+ RB_dworld_step_simulation(rbw->shared->physics_world, timestep, INT_MAX, 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f));
- rigidbody_update_simulation_post_step(rbw);
+ rigidbody_update_simulation_post_step(depsgraph, rbw);
/* write cache for current frame */
BKE_ptcache_validate(cache, (int)ctime);
@@ -1695,14 +1727,14 @@ void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFun
struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; }
struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) { return NULL; }
struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { return NULL; }
-void BKE_rigidbody_remove_object(Scene *scene, Object *ob) {}
+void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob) {}
void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) {}
void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) {}
void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle) {}
bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) { return false; }
void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) {}
-void BKE_rigidbody_rebuild_world(Scene *scene, float ctime) {}
-void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
+void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime) {}
+void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime) {}
#if defined(__GNUC__) || defined(__clang__)
# pragma GCC diagnostic pop
@@ -1710,38 +1742,42 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) {}
#endif /* WITH_BULLET */
+
+
/* -------------------- */
/* Depsgraph evaluation */
-void BKE_rigidbody_rebuild_sim(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_rebuild_sim(Depsgraph *depsgraph,
Scene *scene)
{
- float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime);
/* rebuild sim data (i.e. after resetting to start of timeline) */
if (BKE_scene_check_rigidbody_active(scene)) {
- BKE_rigidbody_rebuild_world(scene, ctime);
+ BKE_rigidbody_rebuild_world(depsgraph, scene, ctime);
}
}
-void BKE_rigidbody_eval_simulation(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_eval_simulation(Depsgraph *depsgraph,
Scene *scene)
{
- float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime);
+
/* evaluate rigidbody sim */
- if (BKE_scene_check_rigidbody_active(scene)) {
- BKE_rigidbody_do_simulation(scene, ctime);
+ if (!BKE_scene_check_rigidbody_active(scene)) {
+ return;
}
+ BKE_rigidbody_do_simulation(depsgraph, scene, ctime);
}
-void BKE_rigidbody_object_sync_transforms(EvaluationContext *UNUSED(eval_ctx),
+void BKE_rigidbody_object_sync_transforms(Depsgraph *depsgraph,
Scene *scene,
Object *ob)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
- float ctime = BKE_scene_frame_get(scene);
- DEG_debug_print_eval_time(__func__, ob->id.name, ob, ctime);
+ float ctime = DEG_get_ctime(depsgraph);
+ DEG_debug_print_eval_time(depsgraph, __func__, ob->id.name, ob, ctime);
/* read values pushed into RBO from sim/cache... */
BKE_rigidbody_sync_transforms(rbw, ob, ctime);
}
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
deleted file mode 100644
index 56e64387096..00000000000
--- a/source/blender/blenkernel/intern/sca.c
+++ /dev/null
@@ -1,1178 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- * these all are linked to objects (listbase)
- * all data is 'direct data', not Blender lib data.
- */
-
-/** \file blender/blenkernel/intern/sca.c
- * \ingroup bke
- */
-
-
-#include <stdio.h>
-#include <string.h>
-#include <float.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_controller_types.h"
-#include "DNA_sensor_types.h"
-#include "DNA_actuator_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_ghash.h"
-#include "BLI_math.h"
-
-#include "BKE_global.h"
-#include "BKE_main.h"
-#include "BKE_library.h"
-#include "BKE_library_query.h"
-#include "BKE_sca.h"
-
-/* ******************* SENSORS ************************ */
-
-void free_sensor(bSensor *sens)
-{
- if (sens->links) MEM_freeN(sens->links);
- if (sens->data) MEM_freeN(sens->data);
- MEM_freeN(sens);
-
-}
-
-void free_sensors(ListBase *lb)
-{
- bSensor *sens;
-
- while ((sens = BLI_pophead(lb))) {
- free_sensor(sens);
- }
-}
-
-bSensor *copy_sensor(bSensor *sens, const int UNUSED(flag))
-{
- bSensor *sensn;
-
- sensn= MEM_dupallocN(sens);
- sensn->flag |= SENS_NEW;
- if (sens->data) {
- sensn->data= MEM_dupallocN(sens->data);
- }
-
- if (sens->links) sensn->links= MEM_dupallocN(sens->links);
-
- return sensn;
-}
-
-void copy_sensors(ListBase *lbn, const ListBase *lbo, const int flag)
-{
- bSensor *sens, *sensn;
-
- lbn->first= lbn->last= NULL;
- sens= lbo->first;
- while (sens) {
- sensn= copy_sensor(sens, flag);
- BLI_addtail(lbn, sensn);
- sens= sens->next;
- }
-}
-
-void init_sensor(bSensor *sens)
-{
- /* also use when sensor changes type */
- bNearSensor *ns;
- bMouseSensor *ms;
- bJoystickSensor *js;
- bRaySensor *rs;
-
- if (sens->data) MEM_freeN(sens->data);
- sens->data= NULL;
- sens->pulse = 0;
-
- switch (sens->type) {
- case SENS_ALWAYS:
- sens->pulse = 0;
- break;
- case SENS_NEAR:
- ns=sens->data= MEM_callocN(sizeof(bNearSensor), "nearsens");
- ns->dist= 1.0;
- ns->resetdist= 2.0;
- break;
- case SENS_KEYBOARD:
- sens->data= MEM_callocN(sizeof(bKeyboardSensor), "keysens");
- break;
- case SENS_PROPERTY:
- sens->data= MEM_callocN(sizeof(bPropertySensor), "propsens");
- break;
- case SENS_ARMATURE:
- sens->data= MEM_callocN(sizeof(bArmatureSensor), "armsens");
- break;
- case SENS_ACTUATOR:
- sens->data= MEM_callocN(sizeof(bActuatorSensor), "actsens");
- break;
- case SENS_DELAY:
- sens->data= MEM_callocN(sizeof(bDelaySensor), "delaysens");
- break;
- case SENS_MOUSE:
- ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens");
- ms->type= 1; // LEFTMOUSE workaround because Mouse Sensor types enum starts in 1
- break;
- case SENS_COLLISION:
- sens->data= MEM_callocN(sizeof(bCollisionSensor), "colsens");
- break;
- case SENS_RADAR:
- sens->data= MEM_callocN(sizeof(bRadarSensor), "radarsens");
- break;
- case SENS_RANDOM:
- sens->data= MEM_callocN(sizeof(bRandomSensor), "randomsens");
- break;
- case SENS_RAY:
- sens->data= MEM_callocN(sizeof(bRaySensor), "raysens");
- rs = sens->data;
- rs->range = 0.01f;
- break;
- case SENS_MESSAGE:
- sens->data= MEM_callocN(sizeof(bMessageSensor), "messagesens");
- break;
- case SENS_JOYSTICK:
- sens->data= MEM_callocN(sizeof(bJoystickSensor), "joysticksens");
- js= sens->data;
- js->hatf = SENS_JOY_HAT_UP;
- js->axis = 1;
- js->hat = 1;
- break;
- default:
- ; /* this is very severe... I cannot make any memory for this */
- /* logic brick... */
- }
-}
-
-bSensor *new_sensor(int type)
-{
- bSensor *sens;
-
- sens= MEM_callocN(sizeof(bSensor), "Sensor");
- sens->type= type;
- sens->flag= SENS_SHOW;
-
- init_sensor(sens);
-
- strcpy(sens->name, "sensor");
-// XXX make_unique_prop_names(sens->name);
-
- return sens;
-}
-
-/* ******************* CONTROLLERS ************************ */
-
-void unlink_controller(bController *cont)
-{
- bSensor *sens;
- Object *ob;
-
- /* check for controller pointers in sensors */
- ob= G.main->object.first;
- while (ob) {
- sens= ob->sensors.first;
- while (sens) {
- unlink_logicbricks((void **)&cont, (void ***)&(sens->links), &sens->totlinks);
- sens= sens->next;
- }
- ob= ob->id.next;
- }
-}
-
-void unlink_controllers(ListBase *lb)
-{
- bController *cont;
-
- for (cont= lb->first; cont; cont= cont->next)
- unlink_controller(cont);
-}
-
-void free_controller(bController *cont)
-{
- if (cont->links) MEM_freeN(cont->links);
-
- /* the controller itself */
- if (cont->data) MEM_freeN(cont->data);
- MEM_freeN(cont);
-
-}
-
-void free_controllers(ListBase *lb)
-{
- bController *cont;
-
- while ((cont = BLI_pophead(lb))) {
- if (cont->slinks)
- MEM_freeN(cont->slinks);
- free_controller(cont);
- }
-}
-
-bController *copy_controller(bController *cont, const int UNUSED(flag))
-{
- bController *contn;
-
- cont->mynew=contn= MEM_dupallocN(cont);
- contn->flag |= CONT_NEW;
- if (cont->data) {
- contn->data= MEM_dupallocN(cont->data);
- }
-
- if (cont->links) contn->links= MEM_dupallocN(cont->links);
- contn->slinks= NULL;
- contn->totslinks= 0;
-
- return contn;
-}
-
-void copy_controllers(ListBase *lbn, const ListBase *lbo, const int flag)
-{
- bController *cont, *contn;
-
- lbn->first= lbn->last= NULL;
- cont= lbo->first;
- while (cont) {
- contn= copy_controller(cont, flag);
- BLI_addtail(lbn, contn);
- cont= cont->next;
- }
-}
-
-void init_controller(bController *cont)
-{
- /* also use when controller changes type, leave actuators... */
-
- if (cont->data) MEM_freeN(cont->data);
- cont->data= NULL;
-
- switch (cont->type) {
- case CONT_EXPRESSION:
- cont->data= MEM_callocN(sizeof(bExpressionCont), "expcont");
- break;
- case CONT_PYTHON:
- cont->data= MEM_callocN(sizeof(bPythonCont), "pycont");
- break;
- }
-}
-
-bController *new_controller(int type)
-{
- bController *cont;
-
- cont= MEM_callocN(sizeof(bController), "Controller");
- cont->type= type;
- cont->flag= CONT_SHOW;
-
- init_controller(cont);
-
- strcpy(cont->name, "cont");
-// XXX make_unique_prop_names(cont->name);
-
- return cont;
-}
-
-/* ******************* ACTUATORS ************************ */
-
-void unlink_actuator(bActuator *act)
-{
- bController *cont;
- Object *ob;
-
- /* check for actuator pointers in controllers */
- ob= G.main->object.first;
- while (ob) {
- cont= ob->controllers.first;
- while (cont) {
- unlink_logicbricks((void **)&act, (void ***)&(cont->links), &cont->totlinks);
- cont= cont->next;
- }
- ob= ob->id.next;
- }
-}
-
-void unlink_actuators(ListBase *lb)
-{
- bActuator *act;
-
- for (act= lb->first; act; act= act->next)
- unlink_actuator(act);
-}
-
-void free_actuator(bActuator *act)
-{
- if (act->data) {
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- {
- bActionActuator *aa = (bActionActuator *)act->data;
- if (aa->act)
- id_us_min((ID *)aa->act);
- break;
- }
- case ACT_SOUND:
- {
- bSoundActuator *sa = (bSoundActuator *) act->data;
- if (sa->sound)
- id_us_min((ID *)sa->sound);
- break;
- }
- }
-
- MEM_freeN(act->data);
- }
- MEM_freeN(act);
-}
-
-void free_actuators(ListBase *lb)
-{
- bActuator *act;
-
- while ((act = BLI_pophead(lb))) {
- free_actuator(act);
- }
-}
-
-bActuator *copy_actuator(bActuator *act, const int flag)
-{
- bActuator *actn;
-
- act->mynew=actn= MEM_dupallocN(act);
- actn->flag |= ACT_NEW;
- if (act->data) {
- actn->data= MEM_dupallocN(act->data);
- }
-
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- {
- bActionActuator *aa = (bActionActuator *)act->data;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)aa->act);
- }
- break;
- }
- case ACT_SOUND:
- {
- bSoundActuator *sa = (bSoundActuator *)act->data;
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)sa->sound);
- }
- break;
- }
- }
- return actn;
-}
-
-void copy_actuators(ListBase *lbn, const ListBase *lbo, const int flag)
-{
- bActuator *act, *actn;
-
- lbn->first= lbn->last= NULL;
- act= lbo->first;
- while (act) {
- actn= copy_actuator(act, flag);
- BLI_addtail(lbn, actn);
- act= act->next;
- }
-}
-
-void init_actuator(bActuator *act)
-{
- /* also use when actuator changes type */
- bCameraActuator *ca;
- bObjectActuator *oa;
- bRandomActuator *ra;
- bSoundActuator *sa;
- bSteeringActuator *sta;
- bArmatureActuator *arma;
- bMouseActuator *ma;
- bEditObjectActuator *eoa;
-
- if (act->data) MEM_freeN(act->data);
- act->data= NULL;
-
- switch (act->type) {
- case ACT_ACTION:
- case ACT_SHAPEACTION:
- act->data= MEM_callocN(sizeof(bActionActuator), "actionact");
- break;
- case ACT_SOUND:
- sa = act->data= MEM_callocN(sizeof(bSoundActuator), "soundact");
- sa->volume = 1.0f;
- sa->sound3D.rolloff_factor = 1.0f;
- sa->sound3D.reference_distance = 1.0f;
- sa->sound3D.max_gain = 1.0f;
- sa->sound3D.cone_inner_angle = DEG2RADF(360.0f);
- sa->sound3D.cone_outer_angle = DEG2RADF(360.0f);
- sa->sound3D.max_distance = FLT_MAX;
- break;
- case ACT_OBJECT:
- act->data= MEM_callocN(sizeof(bObjectActuator), "objectact");
- oa= act->data;
- oa->flag= 15;
- break;
- case ACT_PROPERTY:
- act->data= MEM_callocN(sizeof(bPropertyActuator), "propact");
- break;
- case ACT_CAMERA:
- act->data= MEM_callocN(sizeof(bCameraActuator), "camact");
- ca = act->data;
- ca->axis = OB_POSX;
- ca->damping = 1.0/32.0;
- break;
- case ACT_EDIT_OBJECT:
- act->data= MEM_callocN(sizeof(bEditObjectActuator), "editobact");
- eoa = act->data;
- eoa->upflag= ACT_TRACK_UP_Z;
- eoa->trackflag= ACT_TRACK_TRAXIS_Y;
- break;
- case ACT_CONSTRAINT:
- act->data= MEM_callocN(sizeof(bConstraintActuator), "cons act");
- break;
- case ACT_SCENE:
- act->data= MEM_callocN(sizeof(bSceneActuator), "scene act");
- break;
- case ACT_GROUP:
- act->data= MEM_callocN(sizeof(bGroupActuator), "group act");
- break;
- case ACT_RANDOM:
- act->data= MEM_callocN(sizeof(bRandomActuator), "random act");
- ra=act->data;
- ra->float_arg_1 = 0.1f;
- break;
- case ACT_MESSAGE:
- act->data= MEM_callocN(sizeof(bMessageActuator), "message act");
- break;
- case ACT_GAME:
- act->data= MEM_callocN(sizeof(bGameActuator), "game act");
- break;
- case ACT_VISIBILITY:
- act->data= MEM_callocN(sizeof(bVisibilityActuator), "visibility act");
- break;
- case ACT_2DFILTER:
- act->data = MEM_callocN(sizeof( bTwoDFilterActuator ), "2d filter act");
- break;
- case ACT_PARENT:
- act->data = MEM_callocN(sizeof( bParentActuator ), "parent act");
- break;
- case ACT_STATE:
- act->data = MEM_callocN(sizeof( bStateActuator ), "state act");
- break;
- case ACT_ARMATURE:
- act->data = MEM_callocN(sizeof( bArmatureActuator ), "armature act");
- arma = act->data;
- arma->influence = 1.f;
- break;
- case ACT_STEERING:
- act->data = MEM_callocN(sizeof( bSteeringActuator), "steering act");
- sta = act->data;
- sta->acceleration = 3.f;
- sta->turnspeed = 120.f;
- sta->dist = 1.f;
- sta->velocity= 3.f;
- sta->flag = ACT_STEERING_AUTOMATICFACING | ACT_STEERING_LOCKZVEL;
- sta->facingaxis = 1;
- break;
- case ACT_MOUSE:
- ma = act->data = MEM_callocN(sizeof( bMouseActuator ), "mouse act");
- ma->flag = ACT_MOUSE_VISIBLE|ACT_MOUSE_USE_AXIS_X|ACT_MOUSE_USE_AXIS_Y|ACT_MOUSE_RESET_X|ACT_MOUSE_RESET_Y|ACT_MOUSE_LOCAL_Y;
- ma->sensitivity[0] = ma->sensitivity[1] = 2.f;
- ma->object_axis[0] = ACT_MOUSE_OBJECT_AXIS_Z;
- ma->object_axis[1] = ACT_MOUSE_OBJECT_AXIS_X;
- ma->limit_y[0] = DEG2RADF(-90.0f);
- ma->limit_y[1] = DEG2RADF(90.0f);
- break;
- default:
- ; /* this is very severe... I cannot make any memory for this */
- /* logic brick... */
- }
-}
-
-bActuator *new_actuator(int type)
-{
- bActuator *act;
-
- act= MEM_callocN(sizeof(bActuator), "Actuator");
- act->type= type;
- act->flag= ACT_SHOW;
-
- init_actuator(act);
-
- strcpy(act->name, "act");
-// XXX make_unique_prop_names(act->name);
-
- return act;
-}
-
-/* ******************** GENERAL ******************* */
-void clear_sca_new_poins_ob(Object *ob)
-{
- bSensor *sens;
- bController *cont;
- bActuator *act;
-
- sens= ob->sensors.first;
- while (sens) {
- sens->flag &= ~SENS_NEW;
- sens= sens->next;
- }
- cont= ob->controllers.first;
- while (cont) {
- cont->mynew= NULL;
- cont->flag &= ~CONT_NEW;
- cont= cont->next;
- }
- act= ob->actuators.first;
- while (act) {
- act->mynew= NULL;
- act->flag &= ~ACT_NEW;
- act= act->next;
- }
-}
-
-void clear_sca_new_poins(void)
-{
- Object *ob;
-
- ob= G.main->object.first;
- while (ob) {
- clear_sca_new_poins_ob(ob);
- ob= ob->id.next;
- }
-}
-
-void set_sca_new_poins_ob(Object *ob)
-{
- bSensor *sens;
- bController *cont;
- bActuator *act;
- int a;
-
- sens= ob->sensors.first;
- while (sens) {
- if (sens->flag & SENS_NEW) {
- for (a=0; a<sens->totlinks; a++) {
- if (sens->links[a] && sens->links[a]->mynew)
- sens->links[a] = sens->links[a]->mynew;
- }
- }
- sens= sens->next;
- }
-
- cont= ob->controllers.first;
- while (cont) {
- if (cont->flag & CONT_NEW) {
- for (a=0; a<cont->totlinks; a++) {
- if ( cont->links[a] && cont->links[a]->mynew)
- cont->links[a] = cont->links[a]->mynew;
- }
- }
- cont= cont->next;
- }
-
-
- act= ob->actuators.first;
- while (act) {
- if (act->flag & ACT_NEW) {
- if (act->type==ACT_EDIT_OBJECT) {
- bEditObjectActuator *eoa= act->data;
- ID_NEW_REMAP(eoa->ob);
- }
- else if (act->type==ACT_SCENE) {
- bSceneActuator *sca= act->data;
- ID_NEW_REMAP(sca->camera);
- }
- else if (act->type==ACT_CAMERA) {
- bCameraActuator *ca= act->data;
- ID_NEW_REMAP(ca->ob);
- }
- else if (act->type==ACT_OBJECT) {
- bObjectActuator *oa= act->data;
- ID_NEW_REMAP(oa->reference);
- }
- else if (act->type==ACT_MESSAGE) {
- bMessageActuator *ma= act->data;
- ID_NEW_REMAP(ma->toObject);
- }
- else if (act->type==ACT_PARENT) {
- bParentActuator *para = act->data;
- ID_NEW_REMAP(para->ob);
- }
- else if (act->type==ACT_ARMATURE) {
- bArmatureActuator *aa = act->data;
- ID_NEW_REMAP(aa->target);
- ID_NEW_REMAP(aa->subtarget);
- }
- else if (act->type==ACT_PROPERTY) {
- bPropertyActuator *pa= act->data;
- ID_NEW_REMAP(pa->ob);
- }
- else if (act->type==ACT_STEERING) {
- bSteeringActuator *sta = act->data;
- ID_NEW_REMAP(sta->navmesh);
- ID_NEW_REMAP(sta->target);
- }
- }
- act= act->next;
- }
-}
-
-
-void set_sca_new_poins(void)
-{
- Object *ob;
-
- ob= G.main->object.first;
- while (ob) {
- set_sca_new_poins_ob(ob);
- ob= ob->id.next;
- }
-}
-
-/**
- * Try to remap logic links to new object... Very, *very* weak.
- */
-/* XXX Logick bricks... I don't have words to say what I think about this behavior.
- * They have silent hidden ugly inter-objects dependencies (a sensor can link into any other
- * object's controllers, and same between controllers and actuators, without *any* explicit reference
- * to data-block involved).
- * This is bad, bad, bad!!!
- * ...and forces us to add yet another very ugly hack to get remapping with logic bricks working. */
-void BKE_sca_logic_links_remap(Main *bmain, Object *ob_old, Object *ob_new)
-{
- if (ob_new == NULL || (ob_old->controllers.first == NULL && ob_old->actuators.first == NULL)) {
- /* Nothing to do here... */
- return;
- }
-
- GHash *controllers_map = ob_old->controllers.first ?
- BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->controllers)) : NULL;
- GHash *actuators_map = ob_old->actuators.first ?
- BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&ob_old->actuators)) : NULL;
-
- /* We try to remap old controllers/actuators to new ones - in a very basic way. */
- for (bController *cont_old = ob_old->controllers.first, *cont_new = ob_new->controllers.first;
- cont_old;
- cont_old = cont_old->next)
- {
- bController *cont_new2 = cont_new;
-
- if (cont_old->mynew != NULL) {
- cont_new2 = cont_old->mynew;
- if (!(cont_new2 == cont_new || BLI_findindex(&ob_new->controllers, cont_new2) >= 0)) {
- cont_new2 = NULL;
- }
- }
- else if (cont_new && cont_old->type != cont_new->type) {
- cont_new2 = NULL;
- }
-
- BLI_ghash_insert(controllers_map, cont_old, cont_new2);
-
- if (cont_new) {
- cont_new = cont_new->next;
- }
- }
-
- for (bActuator *act_old = ob_old->actuators.first, *act_new = ob_new->actuators.first;
- act_old;
- act_old = act_old->next)
- {
- bActuator *act_new2 = act_new;
-
- if (act_old->mynew != NULL) {
- act_new2 = act_old->mynew;
- if (!(act_new2 == act_new || BLI_findindex(&ob_new->actuators, act_new2) >= 0)) {
- act_new2 = NULL;
- }
- }
- else if (act_new && act_old->type != act_new->type) {
- act_new2 = NULL;
- }
-
- BLI_ghash_insert(actuators_map, act_old, act_new2);
-
- if (act_new) {
- act_new = act_new->next;
- }
- }
-
- for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
- if (controllers_map != NULL) {
- for (bSensor *sens = ob->sensors.first; sens; sens = sens->next) {
- for (int a = 0; a < sens->totlinks; a++) {
- if (sens->links[a]) {
- bController *old_link = sens->links[a];
- bController **new_link_p = (bController **)BLI_ghash_lookup_p(controllers_map, old_link);
-
- if (new_link_p == NULL) {
- /* old_link is *not* in map's keys (i.e. not to any ob_old->controllers),
- * which means we ignore it totally here. */
- }
- else if (*new_link_p == NULL) {
- unlink_logicbricks((void **)&old_link, (void ***)&(sens->links), &sens->totlinks);
- a--;
- }
- else {
- sens->links[a] = *new_link_p;
- }
- }
- }
- }
- }
-
- if (actuators_map != NULL) {
- for (bController *cont = ob->controllers.first; cont; cont = cont->next) {
- for (int a = 0; a < cont->totlinks; a++) {
- if (cont->links[a]) {
- bActuator *old_link = cont->links[a];
- bActuator **new_link_p = (bActuator **)BLI_ghash_lookup_p(actuators_map, old_link);
-
- if (new_link_p == NULL) {
- /* old_link is *not* in map's keys (i.e. not to any ob_old->actuators),
- * which means we ignore it totally here. */
- }
- else if (*new_link_p == NULL) {
- unlink_logicbricks((void **)&old_link, (void ***)&(cont->links), &cont->totlinks);
- a--;
- }
- else {
- cont->links[a] = *new_link_p;
- }
- }
- }
- }
- }
- }
-
- if (controllers_map) {
- BLI_ghash_free(controllers_map, NULL, NULL);
- }
- if (actuators_map) {
- BLI_ghash_free(actuators_map, NULL, NULL);
- }
-}
-
-/**
- * Handle the copying of logic data into a new object, including internal logic links update.
- * External links (links between logic bricks of different objects) must be handled separately.
- */
-void BKE_sca_logic_copy(Object *ob_new, const Object *ob, const int flag)
-{
- copy_sensors(&ob_new->sensors, &ob->sensors, flag);
- copy_controllers(&ob_new->controllers, &ob->controllers, flag);
- copy_actuators(&ob_new->actuators, &ob->actuators, flag);
-
- for (bSensor *sens = ob_new->sensors.first; sens; sens = sens->next) {
- if (sens->flag & SENS_NEW) {
- for (int a = 0; a < sens->totlinks; a++) {
- if (sens->links[a] && sens->links[a]->mynew) {
- sens->links[a] = sens->links[a]->mynew;
- }
- }
- }
- }
-
- for (bController *cont = ob_new->controllers.first; cont; cont = cont->next) {
- if (cont->flag & CONT_NEW) {
- for (int a = 0; a < cont->totlinks; a++) {
- if (cont->links[a] && cont->links[a]->mynew) {
- cont->links[a] = cont->links[a]->mynew;
- }
- }
- }
- }
-}
-
-/* ******************** INTERFACE ******************* */
-void sca_move_sensor(bSensor *sens_to_move, Object *ob, int move_up)
-{
- bSensor *sens, *tmp;
-
- int val;
- val = move_up ? 1 : 2;
-
- /* make sure this sensor belongs to this object */
- sens= ob->sensors.first;
- while (sens) {
- if (sens == sens_to_move) break;
- sens= sens->next;
- }
- if (!sens) return;
-
- /* move up */
- if (val == 1 && sens->prev) {
- for (tmp=sens->prev; tmp; tmp=tmp->prev) {
- if (tmp->flag & SENS_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->sensors, sens);
- BLI_insertlinkbefore(&ob->sensors, tmp, sens);
- }
- }
- /* move down */
- else if (val == 2 && sens->next) {
- for (tmp=sens->next; tmp; tmp=tmp->next) {
- if (tmp->flag & SENS_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->sensors, sens);
- BLI_insertlinkafter(&ob->sensors, tmp, sens);
- }
- }
-}
-
-void sca_move_controller(bController *cont_to_move, Object *ob, int move_up)
-{
- bController *cont, *tmp;
-
- int val;
- val = move_up ? 1 : 2;
-
- /* make sure this controller belongs to this object */
- cont= ob->controllers.first;
- while (cont) {
- if (cont == cont_to_move) break;
- cont= cont->next;
- }
- if (!cont) return;
-
- /* move up */
- if (val == 1 && cont->prev) {
- /* locate the controller that has the same state mask but is earlier in the list */
- tmp = cont->prev;
- while (tmp) {
- if (tmp->state_mask & cont->state_mask)
- break;
- tmp = tmp->prev;
- }
- if (tmp) {
- BLI_remlink(&ob->controllers, cont);
- BLI_insertlinkbefore(&ob->controllers, tmp, cont);
- }
- }
-
- /* move down */
- else if (val == 2 && cont->next) {
- tmp = cont->next;
- while (tmp) {
- if (tmp->state_mask & cont->state_mask)
- break;
- tmp = tmp->next;
- }
- BLI_remlink(&ob->controllers, cont);
- BLI_insertlinkafter(&ob->controllers, tmp, cont);
- }
-}
-
-void sca_move_actuator(bActuator *act_to_move, Object *ob, int move_up)
-{
- bActuator *act, *tmp;
- int val;
-
- val = move_up ? 1 : 2;
-
- /* make sure this actuator belongs to this object */
- act= ob->actuators.first;
- while (act) {
- if (act == act_to_move) break;
- act= act->next;
- }
- if (!act) return;
-
- /* move up */
- if (val == 1 && act->prev) {
- /* locate the first visible actuators before this one */
- for (tmp = act->prev; tmp; tmp=tmp->prev) {
- if (tmp->flag & ACT_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->actuators, act);
- BLI_insertlinkbefore(&ob->actuators, tmp, act);
- }
- }
- /* move down */
- else if (val == 2 && act->next) {
- /* locate the first visible actuators after this one */
- for (tmp=act->next; tmp; tmp=tmp->next) {
- if (tmp->flag & ACT_VISIBLE)
- break;
- }
- if (tmp) {
- BLI_remlink(&ob->actuators, act);
- BLI_insertlinkafter(&ob->actuators, tmp, act);
- }
- }
-}
-
-void link_logicbricks(void **poin, void ***ppoin, short *tot, short size)
-{
- void **old_links= NULL;
-
- int ibrick;
-
- /* check if the bricks are already linked */
- for (ibrick=0; ibrick < *tot; ibrick++) {
- if ((*ppoin)[ibrick] == *poin)
- return;
- }
-
- if (*ppoin) {
- old_links= *ppoin;
-
- (*tot) ++;
- *ppoin = MEM_callocN((*tot)*size, "new link");
-
- for (ibrick=0; ibrick < *(tot) - 1; ibrick++) {
- (*ppoin)[ibrick] = old_links[ibrick];
- }
- (*ppoin)[ibrick] = *poin;
-
- if (old_links) MEM_freeN(old_links);
- }
- else {
- (*tot) = 1;
- *ppoin = MEM_callocN((*tot)*size, "new link");
- (*ppoin)[0] = *poin;
- }
-}
-
-void unlink_logicbricks(void **poin, void ***ppoin, short *tot)
-{
- int ibrick, removed;
-
- removed= 0;
- for (ibrick=0; ibrick < *tot; ibrick++) {
- if (removed) (*ppoin)[ibrick - removed] = (*ppoin)[ibrick];
- else if ((*ppoin)[ibrick] == *poin) removed = 1;
- }
-
- if (removed) {
- (*tot) --;
-
- if (*tot == 0) {
- MEM_freeN(*ppoin);
- (*ppoin)= NULL;
- }
- return;
- }
-}
-
-void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *userdata)
-{
- bSensor *sensor;
-
- for (sensor = senslist->first; sensor; sensor = sensor->next) {
- func(sensor, (ID **)&sensor->ob, userdata, IDWALK_CB_NOP);
-
- switch (sensor->type) {
- case SENS_TOUCH: /* DEPRECATED */
- {
- bTouchSensor *ts = sensor->data;
- func(sensor, (ID **)&ts->ma, userdata, IDWALK_CB_NOP);
- break;
- }
- case SENS_MESSAGE:
- {
- bMessageSensor *ms = sensor->data;
- func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_CB_NOP);
- break;
- }
- case SENS_ALWAYS:
- case SENS_NEAR:
- case SENS_KEYBOARD:
- case SENS_PROPERTY:
- case SENS_MOUSE:
- case SENS_COLLISION:
- case SENS_RADAR:
- case SENS_RANDOM:
- case SENS_RAY:
- case SENS_JOYSTICK:
- case SENS_ACTUATOR:
- case SENS_DELAY:
- case SENS_ARMATURE:
- default:
- break;
- }
- }
-}
-
-void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, void *userdata)
-{
- bController *controller;
-
- for (controller = contlist->first; controller; controller = controller->next) {
- switch (controller->type) {
- case CONT_PYTHON:
- {
- bPythonCont *pc = controller->data;
- func(controller, (ID **)&pc->text, userdata, IDWALK_CB_NOP);
- break;
- }
- case CONT_LOGIC_AND:
- case CONT_LOGIC_OR:
- case CONT_EXPRESSION:
- case CONT_LOGIC_NAND:
- case CONT_LOGIC_NOR:
- case CONT_LOGIC_XOR:
- case CONT_LOGIC_XNOR:
- default:
- break;
- }
- }
-}
-
-void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void *userdata)
-{
- bActuator *actuator;
-
- for (actuator = actlist->first; actuator; actuator = actuator->next) {
- func(actuator, (ID **)&actuator->ob, userdata, IDWALK_CB_NOP);
-
- switch (actuator->type) {
- case ACT_ADD_OBJECT: /* DEPRECATED */
- {
- bAddObjectActuator *aoa = actuator->data;
- func(actuator, (ID **)&aoa->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_ACTION:
- {
- bActionActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->act, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_SOUND:
- {
- bSoundActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->sound, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_EDIT_OBJECT:
- {
- bEditObjectActuator *eoa = actuator->data;
- func(actuator, (ID **)&eoa->ob, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&eoa->me, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_SCENE:
- {
- bSceneActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->scene, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&sa->camera, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_PROPERTY:
- {
- bPropertyActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_OBJECT:
- {
- bObjectActuator *oa = actuator->data;
- func(actuator, (ID **)&oa->reference, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_CAMERA:
- {
- bCameraActuator *ca = actuator->data;
- func(actuator, (ID **)&ca->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_MESSAGE:
- {
- bMessageActuator *ma = actuator->data;
- func(actuator, (ID **)&ma->toObject, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_2DFILTER:
- {
- bTwoDFilterActuator *tdfa = actuator->data;
- func(actuator, (ID **)&tdfa->text, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_PARENT:
- {
- bParentActuator *pa = actuator->data;
- func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_ARMATURE:
- {
- bArmatureActuator *aa = actuator->data;
- func(actuator, (ID **)&aa->target, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_CB_NOP);
- break;
- }
- case ACT_STEERING:
- {
- bSteeringActuator *sa = actuator->data;
- func(actuator, (ID **)&sa->target, userdata, IDWALK_CB_NOP);
- func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_CB_NOP);
- break;
- }
- /* Note: some types seems to be non-implemented? ACT_LAMP, ACT_MATERIAL... */
- case ACT_LAMP:
- case ACT_MATERIAL:
- case ACT_END_OBJECT: /* DEPRECATED */
- case ACT_CONSTRAINT:
- case ACT_GROUP:
- case ACT_RANDOM:
- case ACT_GAME:
- case ACT_VISIBILITY:
- case ACT_SHAPEACTION:
- case ACT_STATE:
- case ACT_MOUSE:
- default:
- break;
- }
- }
-}
-
-const char *sca_state_name_get(Object *ob, short bit)
-{
- bController *cont;
- unsigned int mask;
-
- mask = (1<<bit);
- cont = ob->controllers.first;
- while (cont) {
- if (cont->state_mask & mask) {
- return cont->name;
- }
- cont = cont->next;
- }
- return NULL;
-}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3a067221aad..af27103b07e 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -37,7 +37,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
-#include "DNA_group_types.h"
+#include "DNA_collection_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
@@ -49,6 +49,7 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_gpencil_types.h"
#include "BLI_math.h"
@@ -67,17 +68,17 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_cachefile.h"
+#include "BKE_collection.h"
#include "BKE_colortools.h"
-#include "BKE_depsgraph.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_group.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
@@ -92,12 +93,18 @@
#include "BKE_sequencer.h"
#include "BKE_sound.h"
#include "BKE_unit.h"
+#include "BKE_workspace.h"
#include "BKE_world.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
#include "RE_engine.h"
+#include "engines/eevee/eevee_lightcache.h"
+
#include "PIL_time.h"
#include "IMB_colormanagement.h"
@@ -105,8 +112,8 @@
#include "bmesh.h"
-const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER";
-const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME";
+const char *RE_engine_id_BLENDER_EEVEE = "BLENDER_EEVEE";
+const char *RE_engine_id_BLENDER_OPENGL = "BLENDER_OPENGL";
const char *RE_engine_id_CYCLES = "CYCLES";
void free_avicodecdata(AviCodecData *acd)
@@ -166,6 +173,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->uvsculpt = MEM_dupallocN(ts->uvsculpt);
BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag);
}
+ if (ts->gp_paint) {
+ ts->gp_paint = MEM_dupallocN(ts->gp_paint);
+ BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag);
+ }
BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
ts->imapaint.paintcursor = NULL;
@@ -173,15 +184,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->particle.scene = NULL;
ts->particle.object = NULL;
- /* duplicate Grease Pencil Drawing Brushes */
- BLI_listbase_clear(&ts->gp_brushes);
- for (bGPDbrush *brush = toolsettings->gp_brushes.first; brush; brush = brush->next) {
- bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush);
- BLI_addtail(&ts->gp_brushes, newbrush);
- }
-
/* duplicate Grease Pencil interpolation curve */
ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo);
+ /* duplicate Grease Pencil multiframe fallof */
+ ts->gp_sculpt.cur_falloff = curvemapping_copy(ts->gp_sculpt.cur_falloff);
return ts;
}
@@ -206,16 +212,20 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
BKE_paint_free(&toolsettings->uvsculpt->paint);
MEM_freeN(toolsettings->uvsculpt);
}
+ if (toolsettings->gp_paint) {
+ BKE_paint_free(&toolsettings->gp_paint->paint);
+ MEM_freeN(toolsettings->gp_paint);
+ }
BKE_paint_free(&toolsettings->imapaint.paint);
- /* free Grease Pencil Drawing Brushes */
- BKE_gpencil_free_brushes(&toolsettings->gp_brushes);
- BLI_freelistN(&toolsettings->gp_brushes);
-
/* free Grease Pencil interpolation curve */
if (toolsettings->gp_interpolate.custom_ipo) {
curvemapping_free(toolsettings->gp_interpolate.custom_ipo);
}
+ /* free Grease Pencil multiframe falloff curve */
+ if (toolsettings->gp_sculpt.cur_falloff) {
+ curvemapping_free(toolsettings->gp_sculpt.cur_falloff);
+ }
MEM_freeN(toolsettings);
}
@@ -234,25 +244,25 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
sce_dst->ed = NULL;
- sce_dst->theDag = NULL;
- sce_dst->depsgraph = NULL;
- sce_dst->obedit = NULL;
- sce_dst->stats = NULL;
+ sce_dst->depsgraph_hash = NULL;
sce_dst->fps_info = NULL;
- BLI_duplicatelist(&(sce_dst->base), &(sce_src->base));
- for (Base *base_dst = sce_dst->base.first, *base_src = sce_src->base.first;
- base_dst;
- base_dst = base_dst->next, base_src = base_src->next)
+ /* Master Collection */
+ if (sce_src->master_collection) {
+ sce_dst->master_collection = BKE_collection_copy_master(bmain, sce_src->master_collection, flag);
+ }
+
+ /* View Layers */
+ BLI_duplicatelist(&sce_dst->view_layers, &sce_src->view_layers);
+ for (ViewLayer *view_layer_src = sce_src->view_layers.first, *view_layer_dst = sce_dst->view_layers.first;
+ view_layer_src;
+ view_layer_src = view_layer_src->next, view_layer_dst = view_layer_dst->next)
{
- if (base_src == sce_src->basact) {
- sce_dst->basact = base_dst;
- }
+ BKE_view_layer_copy_data(sce_dst, sce_src, view_layer_dst, view_layer_src, flag_subdata);
}
BLI_duplicatelist(&(sce_dst->markers), &(sce_src->markers));
BLI_duplicatelist(&(sce_dst->transform_spaces), &(sce_src->transform_spaces));
- BLI_duplicatelist(&(sce_dst->r.layers), &(sce_src->r.layers));
BLI_duplicatelist(&(sce_dst->r.views), &(sce_src->r.views));
BKE_keyingsets_copy(&(sce_dst->keyingsets), &(sce_src->keyingsets));
@@ -267,17 +277,6 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
sce_dst->rigidbody_world = BKE_rigidbody_world_copy(sce_src->rigidbody_world, flag_subdata);
}
- /* copy Freestyle settings */
- for (SceneRenderLayer *srl_dst = sce_dst->r.layers.first, *srl_src = sce_src->r.layers.first;
- srl_src;
- srl_dst = srl_dst->next, srl_src = srl_src->next)
- {
- if (srl_dst->prop != NULL) {
- srl_dst->prop = IDP_CopyProperty_ex(srl_dst->prop, flag_subdata);
- }
- BKE_freestyle_config_copy(&srl_dst->freestyleConfig, &srl_src->freestyleConfig, flag_subdata);
- }
-
/* copy color management settings */
BKE_color_managed_display_settings_copy(&sce_dst->display_settings, &sce_src->display_settings);
BKE_color_managed_view_settings_copy(&sce_dst->view_settings, &sce_src->view_settings);
@@ -322,6 +321,9 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
else {
sce_dst->preview = NULL;
}
+
+ sce_dst->eevee.light_cache = NULL;
+ /* TODO Copy the cache. */
}
Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
@@ -331,20 +333,16 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
/* TODO this should/could most likely be replaced by call to more generic code at some point...
* But for now, let's keep it well isolated here. */
if (type == SCE_COPY_EMPTY) {
- ListBase rl, rv;
+ ListBase rv;
sce_copy = BKE_scene_add(bmain, sce->id.name + 2);
- rl = sce_copy->r.layers;
rv = sce_copy->r.views;
curvemapping_free_data(&sce_copy->r.mblur_shutter_curve);
sce_copy->r = sce->r;
- sce_copy->r.layers = rl;
- sce_copy->r.actlay = 0;
sce_copy->r.views = rv;
sce_copy->unit = sce->unit;
sce_copy->physics_settings = sce->physics_settings;
- sce_copy->gm = sce->gm;
sce_copy->audio = sce->audio;
if (sce->id.properties)
@@ -366,6 +364,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve);
+ /* viewport display settings */
+ sce_copy->display = sce->display;
+
/* tool settings */
sce_copy->toolsettings = BKE_toolsettings_copy(sce->toolsettings, 0);
@@ -399,8 +400,8 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
if (type == SCE_COPY_FULL) {
/* Copy Freestyle LineStyle datablocks. */
- for (SceneRenderLayer *srl_dst = sce_copy->r.layers.first; srl_dst; srl_dst = srl_dst->next) {
- for (FreestyleLineSet *lineset = srl_dst->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ for (ViewLayer *view_layer_dst = sce_copy->view_layers.first; view_layer_dst; view_layer_dst = view_layer_dst->next) {
+ for (FreestyleLineSet *lineset = view_layer_dst->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
if (lineset->linestyle) {
id_us_min(&lineset->linestyle->id);
/* XXX Not copying anim/actions here? */
@@ -415,6 +416,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
BKE_id_copy_ex(bmain, (ID *)sce_copy->world, (ID **)&sce_copy->world, LIB_ID_COPY_ACTIONS, false);
}
+ /* Collections */
+ BKE_collection_copy_full(bmain, sce_copy->master_collection);
+
/* Full copy of GreasePencil. */
/* XXX Not copying anim/actions here? */
if (sce_copy->gpd) {
@@ -430,7 +434,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
}
/* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations
- * are done outside of blenkernel with ED_objects_single_users! */
+ * are done outside of blenkernel with ED_object_single_users! */
/* camera */
/* XXX This is most certainly useless? Object have not yet been duplicated... */
@@ -456,15 +460,11 @@ void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local)
}
/** Free (or release) any data used by this scene (does not free the scene itself). */
-void BKE_scene_free(Scene *sce)
+void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
{
- SceneRenderLayer *srl;
-
BKE_animdata_free((ID *)sce, false);
- sce->basact = NULL;
- BLI_freelistN(&sce->base);
- BKE_sequencer_editing_free(sce, false);
+ BKE_sequencer_editing_free(sce, do_id_user);
BKE_keyingsets_free(&sce->keyingsets);
@@ -476,8 +476,7 @@ void BKE_scene_free(Scene *sce)
}
if (sce->rigidbody_world) {
- BKE_rigidbody_free_world(sce->rigidbody_world);
- sce->rigidbody_world = NULL;
+ BKE_rigidbody_free_world(sce);
}
if (sce->r.avicodecdata) {
@@ -491,27 +490,15 @@ void BKE_scene_free(Scene *sce)
sce->r.ffcodecdata.properties = NULL;
}
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- if (srl->prop != NULL) {
- IDP_FreeProperty(srl->prop);
- MEM_freeN(srl->prop);
- }
- BKE_freestyle_config_free(&srl->freestyleConfig);
- }
-
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->transform_spaces);
- BLI_freelistN(&sce->r.layers);
BLI_freelistN(&sce->r.views);
BKE_toolsettings_free(sce->toolsettings);
sce->toolsettings = NULL;
- DAG_scene_free(sce);
- if (sce->depsgraph)
- DEG_graph_free(sce->depsgraph);
+ BKE_scene_free_depsgraph_hash(sce);
- MEM_SAFE_FREE(sce->stats);
MEM_SAFE_FREE(sce->fps_info);
BKE_sound_destroy_scene(sce);
@@ -520,6 +507,37 @@ void BKE_scene_free(Scene *sce)
BKE_previewimg_free(&sce->preview);
curvemapping_free_data(&sce->r.mblur_shutter_curve);
+
+ for (ViewLayer *view_layer = sce->view_layers.first, *view_layer_next; view_layer; view_layer = view_layer_next) {
+ view_layer_next = view_layer->next;
+
+ BLI_remlink(&sce->view_layers, view_layer);
+ BKE_view_layer_free_ex(view_layer, do_id_user);
+ }
+
+ /* Master Collection */
+ // TODO: what to do with do_id_user? it's also true when just
+ // closing the file which seems wrong? should decrement users
+ // for objects directly in the master collection? then other
+ // collections in the scene need to do it too?
+ if (sce->master_collection) {
+ BKE_collection_free(sce->master_collection);
+ MEM_freeN(sce->master_collection);
+ sce->master_collection = NULL;
+ }
+
+ if (sce->eevee.light_cache) {
+ EEVEE_lightcache_free(sce->eevee.light_cache);
+ sce->eevee.light_cache = NULL;
+ }
+
+ /* These are freed on doversion. */
+ BLI_assert(sce->layer_properties == NULL);
+}
+
+void BKE_scene_free(Scene *sce)
+{
+ BKE_scene_free_ex(sce, true);
}
void BKE_scene_init(Scene *sce)
@@ -532,9 +550,7 @@ void BKE_scene_init(Scene *sce)
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(sce, id));
- sce->lay = sce->layact = 1;
-
- sce->r.mode = R_GAMMA | R_OSA | R_SHADOW | R_SSS | R_ENVMAP | R_RAYTRACE;
+ sce->r.mode = R_OSA;
sce->r.cfra = 1;
sce->r.sfra = 1;
sce->r.efra = 250;
@@ -545,9 +561,7 @@ void BKE_scene_init(Scene *sce)
sce->r.yasp = 1;
sce->r.tilex = 256;
sce->r.tiley = 256;
- sce->r.mblur_samples = 1;
- sce->r.filtertype = R_FILTER_MITCH;
- sce->r.size = 50;
+ sce->r.size = 100;
sce->r.im_format.planes = R_IMF_PLANES_RGBA;
sce->r.im_format.imtype = R_IMF_IMTYPE_PNG;
@@ -555,15 +569,13 @@ void BKE_scene_init(Scene *sce)
sce->r.im_format.quality = 90;
sce->r.im_format.compress = 15;
- sce->r.displaymode = R_OUTPUT_AREA;
+ sce->r.displaymode = R_OUTPUT_WINDOW;
sce->r.framapto = 100;
sce->r.images = 100;
sce->r.framelen = 1.0;
sce->r.blurfac = 0.5;
sce->r.frs_sec = 24;
sce->r.frs_sec_base = 1;
- sce->r.edgeint = 10;
- sce->r.ocres = 128;
/* OCIO_TODO: for forwards compatibility only, so if no tonecurve are used,
* images would look in the same way as in current blender
@@ -572,18 +584,11 @@ void BKE_scene_init(Scene *sce)
*/
sce->r.color_mgt_flag |= R_COLOR_MANAGEMENT;
- sce->r.gauss = 1.0;
-
- /* deprecated but keep for upwards compat */
- sce->r.postgamma = 1.0;
- sce->r.posthue = 0.0;
- sce->r.postsat = 1.0;
+ sce->r.dither_intensity = 1.0f;
- sce->r.bake_mode = 1; /* prevent to include render stuff here */
+ sce->r.bake_mode = 0;
sce->r.bake_filter = 16;
- sce->r.bake_osa = 5;
sce->r.bake_flag = R_BAKE_CLEAR;
- sce->r.bake_normal_space = R_BAKE_SPACE_TANGENT;
sce->r.bake_samples = 256;
sce->r.bake_biasdist = 0.001;
@@ -611,7 +616,6 @@ void BKE_scene_init(Scene *sce)
sce->r.fg_stamp[3] = 1.0f;
sce->r.bg_stamp[0] = sce->r.bg_stamp[1] = sce->r.bg_stamp[2] = 0.0f;
sce->r.bg_stamp[3] = 0.25f;
- sce->r.raytrace_options = R_RAYTRACE_USE_INSTANCES;
sce->r.seq_prev_type = OB_SOLID;
sce->r.seq_rend_type = OB_SOLID;
@@ -621,8 +625,6 @@ void BKE_scene_init(Scene *sce)
sce->r.simplify_subsurf = 6;
sce->r.simplify_particles = 1.0f;
- sce->r.simplify_shadowsamples = 16;
- sce->r.simplify_aosss = 1.0f;
sce->r.border.xmin = 0.0f;
sce->r.border.ymin = 0.0f;
@@ -643,33 +645,25 @@ void BKE_scene_init(Scene *sce)
CURVEMAP_SLOPE_POS_NEG);
sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct");
+
+ sce->toolsettings->object_flag |= SCE_OBJECT_MODE_LOCK;
sce->toolsettings->doublimit = 0.001;
sce->toolsettings->vgroup_weight = 1.0f;
sce->toolsettings->uvcalc_margin = 0.001f;
+ sce->toolsettings->uvcalc_flag = UVCALC_TRANSFORM_CORRECT;
sce->toolsettings->unwrapper = 1;
sce->toolsettings->select_thresh = 0.01f;
+ sce->toolsettings->gizmo_flag = SCE_GIZMO_SHOW_TRANSLATE | SCE_GIZMO_SHOW_ROTATE | SCE_GIZMO_SHOW_SCALE;
sce->toolsettings->selectmode = SCE_SELECT_VERTEX;
sce->toolsettings->uv_selectmode = UV_SELECT_VERTEX;
- sce->toolsettings->normalsize = 0.1;
sce->toolsettings->autokey_mode = U.autokey_mode;
- sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
- sce->toolsettings->skgen_resolution = 100;
- sce->toolsettings->skgen_threshold_internal = 0.01f;
- sce->toolsettings->skgen_threshold_external = 0.01f;
- sce->toolsettings->skgen_angle_limit = 45.0f;
- sce->toolsettings->skgen_length_ratio = 1.3f;
- sce->toolsettings->skgen_length_limit = 1.5f;
- sce->toolsettings->skgen_correlation_limit = 0.98f;
- sce->toolsettings->skgen_symmetry_limit = 0.1f;
- sce->toolsettings->skgen_postpro = SKGEN_SMOOTH;
- sce->toolsettings->skgen_postpro_passes = 1;
- sce->toolsettings->skgen_options = SKGEN_FILTER_INTERNAL | SKGEN_FILTER_EXTERNAL | SKGEN_FILTER_SMART | SKGEN_HARMONIC | SKGEN_SUB_CORRELATION | SKGEN_STICK_TO_EMBEDDING;
- sce->toolsettings->skgen_subdivisions[0] = SKGEN_SUB_CORRELATION;
- sce->toolsettings->skgen_subdivisions[1] = SKGEN_SUB_LENGTH;
- sce->toolsettings->skgen_subdivisions[2] = SKGEN_SUB_ANGLE;
+ sce->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEAN;
+ sce->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT;
+ sce->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID;
+ sce->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT;
sce->toolsettings->curve_paint_settings.curve_type = CU_BEZIER;
sce->toolsettings->curve_paint_settings.flag |= CURVE_PAINT_FLAG_CORNERS_DETECT;
@@ -694,12 +688,25 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->imapaint.normal_angle = 80;
sce->toolsettings->imapaint.seam_bleed = 2;
+ /* grease pencil multiframe falloff curve */
+ sce->toolsettings->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff;
+ curvemapping_initialize(gp_falloff_curve);
+ curvemap_reset(gp_falloff_curve->cm,
+ &gp_falloff_curve->clipr,
+ CURVE_PRESET_GAUSS,
+ CURVEMAP_SLOPE_POSITIVE);
+
sce->physics_settings.gravity[0] = 0.0f;
sce->physics_settings.gravity[1] = 0.0f;
sce->physics_settings.gravity[2] = -9.81f;
sce->physics_settings.flag = PHYS_GLOBAL_GRAVITY;
+ sce->unit.system = USER_UNIT_METRIC;
sce->unit.scale_length = 1.0f;
+ sce->unit.length_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_LENGTH);
+ sce->unit.mass_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_MASS);
+ sce->unit.time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_METRIC, B_UNIT_TIME);
pset = &sce->toolsettings->particle;
pset->flag = PE_KEEP_LENGTHS | PE_LOCK_FIRST | PE_DEFLECT_EMITTER | PE_AUTO_VELOCITY;
@@ -724,12 +731,13 @@ void BKE_scene_init(Scene *sce)
sce->r.ffcodecdata.audio_bitrate = 192;
sce->r.ffcodecdata.audio_channels = 2;
- BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_RENDER, sizeof(sce->r.engine));
+ BLI_strncpy(sce->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(sce->r.engine));
sce->audio.distance_model = 2.0f;
sce->audio.doppler_factor = 1.0f;
sce->audio.speed_of_sound = 343.3f;
sce->audio.volume = 1.0f;
+ sce->audio.flag = AUDIO_SYNC;
BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic));
@@ -737,7 +745,6 @@ void BKE_scene_init(Scene *sce)
sce->r.osa = 8;
/* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
- BKE_scene_add_render_layer(sce, NULL);
/* multiview - stereo */
BKE_scene_add_render_view(sce, STEREO_LEFT_NAME);
@@ -748,59 +755,6 @@ void BKE_scene_init(Scene *sce)
srv = sce->r.views.last;
BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
- /* game data */
- sce->gm.stereoflag = STEREO_NOSTEREO;
- sce->gm.stereomode = STEREO_ANAGLYPH;
- sce->gm.eyeseparation = 0.10;
-
- sce->gm.dome.angle = 180;
- sce->gm.dome.mode = DOME_FISHEYE;
- sce->gm.dome.res = 4;
- sce->gm.dome.resbuf = 1.0f;
- sce->gm.dome.tilt = 0;
-
- sce->gm.xplay = 640;
- sce->gm.yplay = 480;
- sce->gm.freqplay = 60;
- sce->gm.depth = 32;
-
- sce->gm.gravity = 9.8f;
- sce->gm.physicsEngine = WOPHY_BULLET;
- sce->gm.mode = 32; //XXX ugly harcoding, still not sure we should drop mode. 32 == 1 << 5 == use_occlusion_culling
- sce->gm.occlusionRes = 128;
- sce->gm.ticrate = 60;
- sce->gm.maxlogicstep = 5;
- sce->gm.physubstep = 1;
- sce->gm.maxphystep = 5;
- sce->gm.lineardeactthreshold = 0.8f;
- sce->gm.angulardeactthreshold = 1.0f;
- sce->gm.deactivationtime = 0.0f;
-
- sce->gm.flag = GAME_DISPLAY_LISTS;
- sce->gm.matmode = GAME_MAT_MULTITEX;
-
- sce->gm.obstacleSimulation = OBSTSIMULATION_NONE;
- sce->gm.levelHeight = 2.f;
-
- sce->gm.recastData.cellsize = 0.3f;
- sce->gm.recastData.cellheight = 0.2f;
- sce->gm.recastData.agentmaxslope = M_PI_4;
- sce->gm.recastData.agentmaxclimb = 0.9f;
- sce->gm.recastData.agentheight = 2.0f;
- sce->gm.recastData.agentradius = 0.6f;
- sce->gm.recastData.edgemaxlen = 12.0f;
- sce->gm.recastData.edgemaxerror = 1.3f;
- sce->gm.recastData.regionminsize = 8.f;
- sce->gm.recastData.regionmergesize = 20.f;
- sce->gm.recastData.vertsperpoly = 6;
- sce->gm.recastData.detailsampledist = 6.0f;
- sce->gm.recastData.detailsamplemaxerror = 1.0f;
-
- sce->gm.lodflag = SCE_LOD_USE_HYST;
- sce->gm.scehysteresis = 10;
-
- sce->gm.exitkey = 218; // Blender key code for ESC
-
BKE_sound_create_scene(sce);
/* color management */
@@ -823,46 +777,65 @@ void BKE_scene_init(Scene *sce)
{
GP_BrushEdit_Settings *gset = &sce->toolsettings->gp_sculpt;
GP_EditBrush_Data *gp_brush;
+ float curcolor_add[3], curcolor_sub[3];
+ ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
+ ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB];
gp_brush->size = 50;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST];
gp_brush->size = 50;
gp_brush->strength = 0.3f; // XXX?
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH];
gp_brush->size = 50;
gp_brush->strength = 0.5f; // XXX?
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
- gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF;
+ gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR;
+ copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
+ copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
/* GP Stroke Placement */
@@ -870,6 +843,87 @@ void BKE_scene_init(Scene *sce)
sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE;
+
+ /* Annotations */
+ sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR;
+ sce->toolsettings->annotate_thickness = 3;
+
+ sce->orientation_index_custom = -1;
+
+ /* Master Collection */
+ sce->master_collection = BKE_collection_master_add();
+
+ BKE_view_layer_add(sce, "View Layer");
+
+ /* SceneDisplay */
+ copy_v3_v3(sce->display.light_direction, (float[3]){-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3});
+ sce->display.shadow_shift = 0.1;
+
+ sce->display.matcap_ssao_distance = 0.2f;
+ sce->display.matcap_ssao_attenuation = 1.0f;
+ sce->display.matcap_ssao_samples = 16;
+
+ /* OpenGL Render. */
+ BKE_screen_view3d_shading_init(&sce->display.shading);
+
+ /* SceneEEVEE */
+ sce->eevee.gi_diffuse_bounces = 3;
+ sce->eevee.gi_cubemap_resolution = 512;
+ sce->eevee.gi_visibility_resolution = 32;
+ sce->eevee.gi_cubemap_draw_size = 0.3f;
+ sce->eevee.gi_irradiance_draw_size = 0.1f;
+
+ sce->eevee.taa_samples = 16;
+ sce->eevee.taa_render_samples = 64;
+
+ sce->eevee.sss_samples = 7;
+ sce->eevee.sss_jitter_threshold = 0.3f;
+
+ sce->eevee.ssr_quality = 0.25f;
+ sce->eevee.ssr_max_roughness = 0.5f;
+ sce->eevee.ssr_thickness = 0.2f;
+ sce->eevee.ssr_border_fade = 0.075f;
+ sce->eevee.ssr_firefly_fac = 10.0f;
+
+ sce->eevee.volumetric_start = 0.1f;
+ sce->eevee.volumetric_end = 100.0f;
+ sce->eevee.volumetric_tile_size = 8;
+ sce->eevee.volumetric_samples = 64;
+ sce->eevee.volumetric_sample_distribution = 0.8f;
+ sce->eevee.volumetric_light_clamp = 0.0f;
+ sce->eevee.volumetric_shadow_samples = 16;
+
+ sce->eevee.gtao_distance = 0.2f;
+ sce->eevee.gtao_factor = 1.0f;
+ sce->eevee.gtao_quality = 0.25f;
+
+ sce->eevee.bokeh_max_size = 100.0f;
+ sce->eevee.bokeh_threshold = 1.0f;
+
+ copy_v3_fl(sce->eevee.bloom_color, 1.0f);
+ sce->eevee.bloom_threshold = 0.8f;
+ sce->eevee.bloom_knee = 0.5f;
+ sce->eevee.bloom_intensity = 0.8f;
+ sce->eevee.bloom_radius = 6.5f;
+ sce->eevee.bloom_clamp = 1.0f;
+
+ sce->eevee.motion_blur_samples = 8;
+ sce->eevee.motion_blur_shutter = 1.0f;
+
+ sce->eevee.shadow_method = SHADOW_ESM;
+ sce->eevee.shadow_cube_size = 512;
+ sce->eevee.shadow_cascade_size = 1024;
+
+ sce->eevee.light_cache = NULL;
+
+ sce->eevee.overscan = 3.0f;
+
+ sce->eevee.flag =
+ SCE_EEVEE_VOLUMETRIC_LIGHTS |
+ SCE_EEVEE_GTAO_BENT_NORMALS |
+ SCE_EEVEE_GTAO_BOUNCE |
+ SCE_EEVEE_TAA_REPROJECTION |
+ SCE_EEVEE_SSR_HALF_RESOLUTION;
}
Scene *BKE_scene_add(Main *bmain, const char *name)
@@ -885,75 +939,54 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
return sce;
}
-Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name)
+/**
+ * Check if there is any instance of the object in the scene
+ */
+bool BKE_scene_object_find(Scene *scene, Object *ob)
{
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- if (STREQ(base->object->id.name + 2, name)) {
- break;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ if (BLI_findptr(&view_layer->object_bases, ob, offsetof(Base, object))) {
+ return true;
}
}
-
- return base;
+ return false;
}
-Base *BKE_scene_base_find(Scene *scene, Object *ob)
+Object *BKE_scene_object_find_by_name(Scene *scene, const char *name)
{
- return BLI_findptr(&scene->base, ob, offsetof(Base, object));
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ if (STREQ(base->object->id.name + 2, name)) {
+ return base->object;
+ }
+ }
+ }
+ return NULL;
}
/**
* Sets the active scene, mainly used when running in background mode (``--scene`` command line argument).
* This is also called to set the scene directly, bypassing windowing code.
- * Otherwise #ED_screen_set_scene is used when changing scenes by the user.
+ * Otherwise #WM_window_set_active_scene is used when changing scenes by the user.
*/
void BKE_scene_set_background(Main *bmain, Scene *scene)
{
- Scene *sce;
- Base *base;
Object *ob;
- Group *group;
- GroupObject *go;
- int flag;
/* check for cyclic sets, for reading old files but also for definite security (py?) */
BKE_scene_validate_setscene(bmain, scene);
- /* can happen when switching modes in other scenes */
- if (scene->obedit && !(scene->obedit->mode & OB_MODE_EDIT))
- scene->obedit = NULL;
-
/* deselect objects (for dataselect) */
for (ob = bmain->object.first; ob; ob = ob->id.next)
- ob->flag &= ~(SELECT | OB_FROMGROUP);
-
- /* group flags again */
- for (group = bmain->group.first; group; group = group->id.next) {
- for (go = group->gobject.first; go; go = go->next) {
- if (go->ob) {
- go->ob->flag |= OB_FROMGROUP;
- }
- }
- }
-
- /* sort baselist for scene and sets */
- for (sce = scene; sce; sce = sce->set)
- DAG_scene_relations_rebuild(bmain, sce);
+ ob->flag &= ~SELECT;
/* copy layers and flags from bases to objects */
- for (base = scene->base.first; base; base = base->next) {
- ob = base->object;
- ob->lay = base->lay;
-
- /* group patch... */
- base->flag &= ~(OB_FROMGROUP);
- flag = ob->flag & (OB_FROMGROUP);
- base->flag |= flag;
-
- /* not too nice... for recovering objects with lost data */
- //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE;
- ob->flag = base->flag;
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ ob = base->object;
+ /* collection patch... */
+ BKE_scene_object_base_flag_sync_from_base(base);
+ }
}
/* no full animation update, this to enable render code to work (render code calls own animation updates) */
}
@@ -973,8 +1006,8 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name)
}
/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
-int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBaseIter *iter,
- Scene **scene, int val, Base **base, Object **ob)
+int BKE_scene_base_iter_next(Depsgraph *depsgraph, SceneBaseIter *iter,
+ Scene **scene, int val, Base **base, Object **ob)
{
bool run_again = true;
@@ -992,17 +1025,21 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
/* the first base */
if (iter->phase == F_START) {
- *base = (*scene)->base.first;
+ ViewLayer *view_layer = (depsgraph) ?
+ DEG_get_evaluated_view_layer(depsgraph) :
+ BKE_view_layer_context_active_PLACEHOLDER(*scene);
+ *base = view_layer->object_bases.first;
if (*base) {
*ob = (*base)->object;
iter->phase = F_SCENE;
}
else {
- /* exception: empty scene */
+ /* exception: empty scene layer */
while ((*scene)->set) {
(*scene) = (*scene)->set;
- if ((*scene)->base.first) {
- *base = (*scene)->base.first;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
+ if (view_layer_set->object_bases.first) {
+ *base = view_layer_set->object_bases.first;
*ob = (*base)->object;
iter->phase = F_SCENE;
break;
@@ -1021,8 +1058,9 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
/* (*scene) is finished, now do the set */
while ((*scene)->set) {
(*scene) = (*scene)->set;
- if ((*scene)->base.first) {
- *base = (*scene)->base.first;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*scene));
+ if (view_layer_set->object_bases.first) {
+ *base = view_layer_set->object_bases.first;
*ob = (*base)->object;
break;
}
@@ -1037,12 +1075,12 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
else {
if (iter->phase != F_DUPLI) {
- if ( (*base)->object->transflag & OB_DUPLI) {
- /* groups cannot be duplicated for mballs yet,
+ if (depsgraph && (*base)->object->transflag & OB_DUPLI) {
+ /* collections cannot be duplicated for mballs yet,
* this enters eternal loop because of
- * makeDispListMBall getting called inside of group_duplilist */
+ * makeDispListMBall getting called inside of collection_duplilist */
if ((*base)->object->dup_group == NULL) {
- iter->duplilist = object_duplilist_ex(bmain, eval_ctx, (*scene), (*base)->object, false);
+ iter->duplilist = object_duplilist(depsgraph, (*scene), (*base)->object);
iter->dupob = iter->duplilist->first;
@@ -1056,7 +1094,7 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
/* handle dupli's */
if (iter->dupob) {
- (*base)->flag |= OB_FROMDUPLI;
+ (*base)->flag_legacy |= OB_FROMDUPLI;
*ob = iter->dupob->ob;
iter->phase = F_DUPLI;
@@ -1075,7 +1113,7 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
else if (iter->phase == F_DUPLI) {
iter->phase = F_SCENE;
- (*base)->flag &= ~OB_FROMDUPLI;
+ (*base)->flag_legacy &= ~OB_FROMDUPLI;
if (iter->dupli_refob) {
/* Restore last object's real matrix. */
@@ -1091,22 +1129,18 @@ int BKE_scene_base_iter_next(Main *bmain, EvaluationContext *eval_ctx, SceneBase
}
}
-#if 0
- if (ob && *ob) {
- printf("Scene: '%s', '%s'\n", (*scene)->id.name + 2, (*ob)->id.name + 2);
- }
-#endif
-
return iter->phase;
}
-Object *BKE_scene_camera_find(Scene *sc)
+Scene *BKE_scene_find_from_collection(const Main *bmain, const Collection *collection)
{
- Base *base;
-
- for (base = sc->base.first; base; base = base->next)
- if (base->object->type == OB_CAMERA)
- return base->object;
+ for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) {
+ for (ViewLayer *layer = scene->view_layers.first; layer; layer = layer->next) {
+ if (BKE_view_layer_has_collection(layer, collection)) {
+ return scene;
+ }
+ }
+ }
return NULL;
}
@@ -1160,6 +1194,7 @@ int BKE_scene_camera_switch_update(Scene *scene)
Object *camera = BKE_scene_camera_switch_find(scene);
if (camera) {
scene->camera = camera;
+ DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
return 1;
}
#else
@@ -1218,49 +1253,14 @@ int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, in
return (delta_prev < delta_next) ? second_prev : second_next;
}
-
-Base *BKE_scene_base_add(Scene *sce, Object *ob)
-{
- Base *b = MEM_callocN(sizeof(*b), __func__);
- BLI_addhead(&sce->base, b);
-
- b->object = ob;
- b->flag = ob->flag;
- b->lay = ob->lay;
-
- return b;
-}
-
-void BKE_scene_base_unlink(Scene *sce, Base *base)
+void BKE_scene_remove_rigidbody_object(struct Main *bmain, Scene *scene, Object *ob)
{
/* remove rigid body constraint from world before removing object */
- if (base->object->rigidbody_constraint)
- BKE_rigidbody_remove_constraint(sce, base->object);
+ if (ob->rigidbody_constraint)
+ BKE_rigidbody_remove_constraint(scene, ob);
/* remove rigid body object from world before removing object */
- if (base->object->rigidbody_object)
- BKE_rigidbody_remove_object(sce, base->object);
-
- BLI_remlink(&sce->base, base);
- if (sce->basact == base)
- sce->basact = NULL;
-}
-
-void BKE_scene_base_deselect_all(Scene *sce)
-{
- Base *b;
-
- for (b = sce->base.first; b; b = b->next) {
- b->flag &= ~SELECT;
- b->object->flag = b->flag;
- }
-}
-
-void BKE_scene_base_select(Scene *sce, Base *selbase)
-{
- selbase->flag |= SELECT;
- selbase->object->flag = selbase->flag;
-
- sce->basact = selbase;
+ if (ob->rigidbody_object)
+ BKE_rigidbody_remove_object(bmain, scene, ob);
}
/* checks for cycle, returns 1 if it's all OK */
@@ -1312,109 +1312,6 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra)
scene->r.cfra = (int)intpart;
}
-#ifdef WITH_LEGACY_DEPSGRAPH
-/* drivers support/hacks
- * - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render
- * - these are always run since the depsgraph can't handle non-object data
- * - these happen after objects are all done so that we can read in their final transform values,
- * though this means that objects can't refer to scene info for guidance...
- */
-static void scene_update_drivers(Main *UNUSED(bmain), Scene *scene)
-{
- SceneRenderLayer *srl;
- float ctime = BKE_scene_frame_get(scene);
-
- /* scene itself */
- if (scene->adt && scene->adt->drivers.first) {
- BKE_animsys_evaluate_animdata(scene, &scene->id, scene->adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* world */
- /* TODO: what about world textures? but then those have nodes too... */
- if (scene->world) {
- ID *wid = (ID *)scene->world;
- AnimData *adt = BKE_animdata_from_id(wid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, wid, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* nodes */
- if (scene->nodetree) {
- ID *nid = (ID *)scene->nodetree;
- AnimData *adt = BKE_animdata_from_id(nid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* world nodes */
- if (scene->world && scene->world->nodetree) {
- ID *nid = (ID *)scene->world->nodetree;
- AnimData *adt = BKE_animdata_from_id(nid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, nid, adt, ctime, ADT_RECALC_DRIVERS);
- }
-
- /* freestyle */
- for (srl = scene->r.layers.first; srl; srl = srl->next) {
- FreestyleConfig *config = &srl->freestyleConfig;
- FreestyleLineSet *lineset;
-
- for (lineset = config->linesets.first; lineset; lineset = lineset->next) {
- if (lineset->linestyle) {
- ID *lid = &lineset->linestyle->id;
- AnimData *adt = BKE_animdata_from_id(lid);
-
- if (adt && adt->drivers.first)
- BKE_animsys_evaluate_animdata(scene, lid, adt, ctime, ADT_RECALC_DRIVERS);
- }
- }
- }
-}
-
-/* deps hack - do extra recalcs at end */
-static void scene_depsgraph_hack(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent)
-{
- Base *base;
-
- scene->customdata_mask = scene_parent->customdata_mask;
-
- /* sets first, we allow per definition current scene to have
- * dependencies on sets, but not the other way around. */
- if (scene->set)
- scene_depsgraph_hack(bmain, eval_ctx, scene->set, scene_parent);
-
- for (base = scene->base.first; base; base = base->next) {
- Object *ob = base->object;
-
- if (ob->depsflag) {
- int recalc = 0;
- // printf("depshack %s\n", ob->id.name + 2);
-
- if (ob->depsflag & OB_DEPS_EXTRA_OB_RECALC)
- recalc |= OB_RECALC_OB;
- if (ob->depsflag & OB_DEPS_EXTRA_DATA_RECALC)
- recalc |= OB_RECALC_DATA;
-
- ob->recalc |= recalc;
- BKE_object_handle_update(bmain, eval_ctx, scene_parent, ob);
-
- if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP)) {
- GroupObject *go;
-
- for (go = ob->dup_group->gobject.first; go; go = go->next) {
- if (go->ob)
- go->ob->recalc |= recalc;
- }
- BKE_group_handle_recalc_and_update(bmain, eval_ctx, scene_parent, ob, ob->dup_group);
- }
- }
- }
-}
-#endif /* WITH_LEGACY_DEPSGRAPH */
-
/* That's like really a bummer, because currently animation data for armatures
* might want to use pose, and pose might be missing on the object.
* This happens when changing visible layers, which leads to situations when
@@ -1427,392 +1324,41 @@ static void scene_depsgraph_hack(Main *bmain, EvaluationContext *eval_ctx, Scene
#define POSE_ANIMATION_WORKAROUND
#ifdef POSE_ANIMATION_WORKAROUND
-static void scene_armature_depsgraph_workaround(Main *bmain)
+static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgraph)
{
Object *ob;
- if (BLI_listbase_is_empty(&bmain->armature) || !DAG_id_type_tagged(bmain, ID_OB)) {
+ if (BLI_listbase_is_empty(&bmain->armature) || !DEG_id_type_updated(depsgraph, ID_OB)) {
return;
}
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->type == OB_ARMATURE && ob->adt && ob->adt->recalc & ADT_RECALC_ANIM) {
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
- BKE_pose_rebuild(ob, ob->data);
- }
- }
- }
-}
-#endif
-
-#ifdef WITH_LEGACY_DEPSGRAPH
-static void scene_rebuild_rbw_recursive(Scene *scene, float ctime)
-{
- if (scene->set)
- scene_rebuild_rbw_recursive(scene->set, ctime);
-
- if (BKE_scene_check_rigidbody_active(scene))
- BKE_rigidbody_rebuild_world(scene, ctime);
-}
-
-static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
-{
- if (scene->set)
- scene_do_rb_simulation_recursive(scene->set, ctime);
-
- if (BKE_scene_check_rigidbody_active(scene))
- BKE_rigidbody_do_simulation(scene, ctime);
-}
-#endif
-
-/* Used to visualize CPU threads activity during threaded object update,
- * would pollute STDERR with whole bunch of timing information which then
- * could be parsed and nicely visualized.
- */
-#ifdef WITH_LEGACY_DEPSGRAPH
-# undef DETAILED_ANALYSIS_OUTPUT
-#else
-/* ALWAYS KEEY DISABLED! */
-# undef DETAILED_ANALYSIS_OUTPUT
-#endif
-
-/* Mballs evaluation uses BKE_scene_base_iter_next which calls
- * duplilist for all objects in the scene. This leads to conflict
- * accessing and writing same data from multiple threads.
- *
- * Ideally Mballs shouldn't do such an iteration and use DAG
- * queries instead. For the time being we've got new DAG
- * let's keep it simple and update mballs in a single thread.
- */
-#define MBALL_SINGLETHREAD_HACK
-
-#ifdef WITH_LEGACY_DEPSGRAPH
-typedef struct StatisicsEntry {
- struct StatisicsEntry *next, *prev;
- Object *object;
- double start_time;
- double duration;
-} StatisicsEntry;
-
-typedef struct ThreadedObjectUpdateState {
- /* TODO(sergey): We might want this to be per-thread object. */
- EvaluationContext *eval_ctx;
- Main *bmain;
- Scene *scene;
- Scene *scene_parent;
- double base_time;
-
-#ifdef MBALL_SINGLETHREAD_HACK
- bool has_mballs;
-#endif
-
- int num_threads;
-
- /* Execution statistics */
- bool has_updated_objects;
- ListBase *statistics;
-} ThreadedObjectUpdateState;
-
-static void scene_update_object_add_task(void *node, void *user_data);
-
-static void scene_update_all_bases(Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Scene *scene_parent)
-{
- Base *base;
-
- for (base = scene->base.first; base; base = base->next) {
- Object *object = base->object;
-
- BKE_object_handle_update_ex(bmain, eval_ctx, scene_parent, object, scene->rigidbody_world, true);
-
- if (object->dup_group && (object->transflag & OB_DUPLIGROUP))
- BKE_group_handle_recalc_and_update(bmain, eval_ctx, scene_parent, object, object->dup_group);
-
- /* always update layer, so that animating layers works (joshua july 2010) */
- /* XXX commented out, this has depsgraph issues anyway - and this breaks setting scenes
- * (on scene-set, the base-lay is copied to ob-lay (ton nov 2012) */
- // base->lay = ob->lay;
- }
-}
-
-static void scene_update_object_func(TaskPool * __restrict pool, void *taskdata, int threadid)
-{
-/* Disable print for now in favor of summary statistics at the end of update. */
-#define PRINT if (false) printf
-
- ThreadedObjectUpdateState *state = (ThreadedObjectUpdateState *) BLI_task_pool_userdata(pool);
- void *node = taskdata;
- Object *object = DAG_get_node_object(node);
- EvaluationContext *eval_ctx = state->eval_ctx;
- Main *bmain = state->bmain;
- Scene *scene = state->scene;
- Scene *scene_parent = state->scene_parent;
-
-#ifdef MBALL_SINGLETHREAD_HACK
- if (object && object->type == OB_MBALL) {
- state->has_mballs = true;
- }
- else
-#endif
- if (object) {
- double start_time = 0.0;
- bool add_to_stats = false;
-
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- if (object->recalc & OB_RECALC_ALL) {
- printf("Thread %d: update object %s\n", threadid, object->id.name);
- }
-
- start_time = PIL_check_seconds_timer();
-
- if (object->recalc & OB_RECALC_ALL) {
- state->has_updated_objects = true;
- add_to_stats = true;
+ BKE_pose_rebuild(bmain, ob, ob->data, true);
}
}
-
- /* We only update object itself here, dupli-group will be updated
- * separately from main thread because of we've got no idea about
- * dependencies inside the group.
- */
- BKE_object_handle_update_ex(bmain, eval_ctx, scene_parent, object, scene->rigidbody_world, false);
-
- /* Calculate statistics. */
- if (add_to_stats) {
- StatisicsEntry *entry;
-
- entry = MEM_mallocN(sizeof(StatisicsEntry), "update thread statistics");
- entry->object = object;
- entry->start_time = start_time;
- entry->duration = PIL_check_seconds_timer() - start_time;
-
- BLI_addtail(&state->statistics[threadid], entry);
- }
}
- else {
- PRINT("Threda %d: update node %s\n", threadid,
- DAG_get_node_name(scene, node));
- }
-
- /* Update will decrease child's valency and schedule child with zero valency. */
- DAG_threaded_update_handle_node_updated(node, scene_update_object_add_task, pool);
-
-#undef PRINT
-}
-
-static void scene_update_object_add_task(void *node, void *user_data)
-{
- TaskPool *task_pool = user_data;
-
- BLI_task_pool_push(task_pool, scene_update_object_func, node, false, TASK_PRIORITY_LOW);
}
-
-static void print_threads_statistics(ThreadedObjectUpdateState *state)
-{
- double finish_time;
-
- if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) {
- return;
- }
-
-#ifdef DETAILED_ANALYSIS_OUTPUT
- if (state->has_updated_objects) {
- tot_thread = BLI_system_thread_count();
-
- fprintf(stderr, "objects update base time %f\n", state->base_time);
-
- for (i = 0; i < tot_thread; i++) {
- StatisicsEntry *entry;
- for (entry = state->statistics[i].first;
- entry;
- entry = entry->next)
- {
- fprintf(stderr, "thread %d object %s start_time %f duration %f\n",
- i, entry->object->id.name + 2,
- entry->start_time, entry->duration);
- }
- BLI_freelistN(&state->statistics[i]);
- }
- }
-#else
- finish_time = PIL_check_seconds_timer();
- int total_objects = 0;
-
- for (int i = 0; i < state->num_threads; i++) {
- int thread_total_objects = 0;
- double thread_total_time = 0.0;
- StatisicsEntry *entry;
-
- if (state->has_updated_objects) {
- /* Don't pollute output if no objects were updated. */
- for (entry = state->statistics[i].first;
- entry;
- entry = entry->next)
- {
- thread_total_objects++;
- thread_total_time += entry->duration;
- }
-
- printf("Thread %d: total %d objects in %f sec.\n",
- i,
- thread_total_objects,
- thread_total_time);
-
- for (entry = state->statistics[i].first;
- entry;
- entry = entry->next)
- {
- printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration);
- }
-
- total_objects += thread_total_objects;
- }
-
- BLI_freelistN(&state->statistics[i]);
- }
- if (state->has_updated_objects) {
- printf("Scene updated %d objects in %f sec\n",
- total_objects,
- finish_time - state->base_time);
- }
#endif
-}
-
-static bool scene_need_update_objects(Main *bmain)
-{
- return
- /* Object datablocks themselves (for OB_RECALC_OB) */
- DAG_id_type_tagged(bmain, ID_OB) ||
-
- /* Objects data datablocks (for OB_RECALC_DATA) */
- DAG_id_type_tagged(bmain, ID_ME) || /* Mesh */
- DAG_id_type_tagged(bmain, ID_CU) || /* Curve */
- DAG_id_type_tagged(bmain, ID_MB) || /* MetaBall */
- DAG_id_type_tagged(bmain, ID_LA) || /* Lamp */
- DAG_id_type_tagged(bmain, ID_LT) || /* Lattice */
- DAG_id_type_tagged(bmain, ID_CA) || /* Camera */
- DAG_id_type_tagged(bmain, ID_KE) || /* KE */
- DAG_id_type_tagged(bmain, ID_SPK) || /* Speaker */
- DAG_id_type_tagged(bmain, ID_AR); /* Armature */
-}
-
-static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
-{
- TaskScheduler *task_scheduler;
- TaskPool *task_pool;
- ThreadedObjectUpdateState state;
- bool need_singlethread_pass;
- bool need_free_scheduler;
-
- /* Early check for whether we need to invoke all the task-based
- * things (spawn new ppol, traverse dependency graph and so on).
- *
- * Basically if there's no ID datablocks tagged for update which
- * corresponds to object->recalc flags (which are checked in
- * BKE_object_handle_update() then we do nothing here.
- */
- if (!scene_need_update_objects(bmain)) {
- return;
- }
-
- state.eval_ctx = eval_ctx;
- state.bmain = bmain;
- state.scene = scene;
- state.scene_parent = scene_parent;
-
- if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
- task_scheduler = BLI_task_scheduler_create(1);
- need_free_scheduler = true;
- }
- else {
- task_scheduler = BLI_task_scheduler_get();
- need_free_scheduler = false;
- }
-
- /* Those are only needed when blender is run with --debug argument. */
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- const int tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
- state.statistics = MEM_callocN(tot_thread * sizeof(*state.statistics),
- "scene update objects stats");
- state.has_updated_objects = false;
- state.base_time = PIL_check_seconds_timer();
- state.num_threads = tot_thread;
- }
-
-#ifdef MBALL_SINGLETHREAD_HACK
- state.has_mballs = false;
-#endif
-
- task_pool = BLI_task_pool_create(task_scheduler, &state);
-
- DAG_threaded_update_begin(scene, scene_update_object_add_task, task_pool);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) {
- print_threads_statistics(&state);
- MEM_freeN(state.statistics);
- }
-
- /* We do single thread pass to update all the objects which are in cyclic dependency.
- * Such objects can not be handled by a generic DAG traverse and it's really tricky
- * to detect whether cycle could be solved or not.
- *
- * In this situation we simply update all remaining objects in a single thread and
- * it'll happen in the same exact order as it was in single-threaded DAG.
- *
- * We couldn't use threaded update for objects which are in cycle because they might
- * access data of each other which is being re-evaluated.
- *
- * Also, as was explained above, for now we also update all the mballs in single thread.
- *
- * - sergey -
- */
- need_singlethread_pass = DAG_is_acyclic(scene) == false;
-#ifdef MBALL_SINGLETHREAD_HACK
- need_singlethread_pass |= state.has_mballs;
-#endif
-
- if (need_singlethread_pass) {
- scene_update_all_bases(bmain, eval_ctx, scene, scene_parent);
- }
-
- if (need_free_scheduler) {
- BLI_task_scheduler_free(task_scheduler);
- }
-}
-
-static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bmain, Scene *scene, Scene *scene_parent)
-{
- scene->customdata_mask = scene_parent->customdata_mask;
-
- /* sets first, we allow per definition current scene to have
- * dependencies on sets, but not the other way around. */
- if (scene->set)
- scene_update_tagged_recursive(eval_ctx, bmain, scene->set, scene_parent);
-
- /* scene objects */
- scene_update_objects(eval_ctx, bmain, scene, scene_parent);
-
- /* scene drivers... */
- scene_update_drivers(bmain, scene);
-
- /* update masking curves */
- BKE_mask_update_scene(bmain, scene);
-
-}
-#endif /* WITH_LEGACY_DEPSGRAPH */
static bool check_rendered_viewport_visible(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
wmWindow *window;
for (window = wm->windows.first; window != NULL; window = window->next) {
- bScreen *screen = window->screen;
- ScrArea *area;
- for (area = screen->areabase.first; area != NULL; area = area->next) {
+ const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
+ Scene *scene = window->scene;
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+
+ if (type->draw_engine || !type->render) {
+ continue;
+ }
+
+ for (ScrArea *area = screen->areabase.first; area != NULL; area = area->next) {
View3D *v3d = area->spacedata.first;
if (area->spacetype != SPACE_VIEW3D) {
continue;
}
- if (v3d->drawtype == OB_RENDER) {
+ if (v3d->shading.type == OB_RENDER) {
return true;
}
}
@@ -1820,7 +1366,10 @@ static bool check_rendered_viewport_visible(Main *bmain)
return false;
}
-static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
+/* TODO(campbell): shouldn't we be able to use 'DEG_get_view_layer' here?
+ * Currently this is NULL on load, so don't. */
+static void prepare_mesh_for_viewport_render(
+ Main *bmain, const ViewLayer *view_layer)
{
/* This is needed to prepare mesh to be used by the render
* engine from the viewport rendering. We do loading here
@@ -1831,7 +1380,7 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
* call loading of the edit data for the mesh objects.
*/
- Object *obedit = scene->obedit;
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (obedit) {
Mesh *mesh = obedit->data;
if ((obedit->type == OB_MESH) &&
@@ -1845,318 +1394,96 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
(&(struct BMeshToMeshParams){
.calc_object_remap = true,
}));
- DAG_id_tag_update(&mesh->id, 0);
+ DEG_id_tag_update(&mesh->id, 0);
}
}
}
}
-void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
+/* TODO(sergey): This actually should become view_layer_graph or so.
+ * Same applies to update_for_newframe.
+ */
+void BKE_scene_graph_update_tagged(Depsgraph *depsgraph,
+ Main *bmain)
{
- Scene *sce_iter;
-#ifdef WITH_LEGACY_DEPSGRAPH
- bool use_new_eval = !DEG_depsgraph_use_legacy();
-#endif
-
- /* keep this first */
- BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
- /* (re-)build dependency graph if needed */
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) {
- DAG_scene_relations_update(bmain, sce_iter);
- /* Uncomment this to check if dependency graph was properly tagged for update. */
-#if 0
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (use_new_eval)
-#endif
- {
- DAG_scene_relations_validate(bmain, sce_iter);
- }
-#endif
- }
-
- /* flush editing data if needed */
- prepare_mesh_for_viewport_render(bmain, scene);
-
- /* flush recalc flags to dependencies */
- DAG_ids_flush_tagged(bmain);
-
- /* removed calls to quick_cache, see pointcache.c */
-
- /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later
- * when trying to find materials with drivers that need evaluating [#32017]
+ /* TODO(sergey): Some functions here are changing global state,
+ * for example, clearing update tags from bmain.
*/
- BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
-
- /* update all objects: drivers, matrices, displists, etc. flags set
- * by depgraph or manual, no layer check here, gets correct flushed
- *
- * in the future this should handle updates for all datablocks, not
- * only objects and scenes. - brecht */
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
- }
- else
-#endif
- {
- DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
- }
-
- /* update sound system animation (TODO, move to depsgraph) */
- BKE_sound_update_scene(bmain, scene);
-
- /* extra call here to recalc scene animation (for sequencer) */
- {
- AnimData *adt = BKE_animdata_from_id(&scene->id);
- float ctime = BKE_scene_frame_get(scene);
-
- if (adt && (adt->recalc & ADT_RECALC_ANIM))
- BKE_animsys_evaluate_animdata(scene, &scene->id, adt, ctime, 0);
- }
-
- /* Extra call here to recalc material animation.
- *
- * Need to do this so changing material settings from the graph/dopesheet
- * will update stuff in the viewport.
+ /* (Re-)build dependency graph if needed. */
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Uncomment this to check if graph was properly tagged for update. */
+ // DEG_debug_graph_relations_validate(depsgraph, bmain, scene);
+ /* Flush editing data if needed. */
+ prepare_mesh_for_viewport_render(bmain, view_layer);
+ /* Flush recalc flags to dependencies. */
+ DEG_graph_flush_update(bmain, depsgraph);
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
*/
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) {
- Material *material;
- float ctime = BKE_scene_frame_get(scene);
-
- for (material = bmain->mat.first;
- material;
- material = material->id.next)
- {
- AnimData *adt = BKE_animdata_from_id(&material->id);
- if (adt && (adt->recalc & ADT_RECALC_ANIM))
- BKE_animsys_evaluate_animdata(scene, &material->id, adt, ctime, 0);
- }
- }
-
- /* Also do the same for node trees. */
- if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) {
- float ctime = BKE_scene_frame_get(scene);
-
- 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);
-
+ DEG_evaluate_on_refresh(depsgraph);
+ /* Update sound system animation (TODO, move to depsgraph). */
+ BKE_sound_update_scene(bmain, scene);
/* Inform editors about possible changes. */
- DAG_ids_check_recalc(bmain, scene, false);
-
- /* clear recalc flags */
- DAG_ids_clear_recalc(bmain);
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, false);
+ /* Clear recalc flags. */
+ DEG_ids_clear_recalc(bmain, depsgraph);
}
/* applies changes right away, does all sets too */
-void BKE_scene_update_for_newframe(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay)
-{
- BKE_scene_update_for_newframe_ex(eval_ctx, bmain, sce, lay, false);
-}
-
-void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain, Scene *sce, unsigned int lay, bool do_invisible_flush)
+void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph,
+ Main *bmain)
{
- float ctime = BKE_scene_frame_get(sce);
- Scene *sce_iter;
-#ifdef DETAILED_ANALYSIS_OUTPUT
- double start_time = PIL_check_seconds_timer();
-#endif
-#ifdef WITH_LEGACY_DEPSGRAPH
- bool use_new_eval = !DEG_depsgraph_use_legacy();
-#else
- /* TODO(sergey): Pass to evaluation routines instead of storing layer in the dependency graph? */
- (void) do_invisible_flush;
-#endif
-
- DAG_editors_update_pre(bmain, sce, true);
-
- /* keep this first */
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
-
- /* update animated image textures for particles, modifiers, gpu, etc,
- * call this at the start so modifiers with textures don't lag 1 frame */
- BKE_image_update_frame(bmain, sce->r.cfra);
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
-#ifdef WITH_LEGACY_DEPSGRAPH
- /* rebuild rigid body worlds before doing the actual frame update
- * this needs to be done on start frame but animation playback usually starts one frame later
- * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
+ /* TODO(sergey): Some functions here are changing global state,
+ * for example, clearing update tags from bmain.
*/
- if (!use_new_eval) {
- scene_rebuild_rbw_recursive(sce, ctime);
- }
-#endif
-
- BKE_sound_set_cfra(sce->r.cfra);
-
- /* clear animation overrides */
- /* XXX TODO... */
-
- for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
- DAG_scene_relations_update(bmain, sce_iter);
-
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- /* flush recalc flags to dependencies, if we were only changing a frame
- * this would not be necessary, but if a user or a script has modified
- * some datablock before BKE_scene_update_tagged was called, we need the flush */
- DAG_ids_flush_tagged(bmain);
-
- /* Following 2 functions are recursive
- * so don't call within 'scene_update_tagged_recursive' */
- DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
- BKE_mask_evaluate_all_masks(bmain, ctime, true);
- }
-#endif
-
- /* Update animated cache files for modifiers. */
- BKE_cachefile_update_frame(bmain, sce, ctime, (((double)sce->r.frs_sec) / (double)sce->r.frs_sec_base));
-
-#ifdef POSE_ANIMATION_WORKAROUND
- scene_armature_depsgraph_workaround(bmain);
-#endif
-
- /* All 'standard' (i.e. without any dependencies) animation is handled here,
- * with an 'local' to 'macro' order of evaluation. This should ensure that
- * settings stored nestled within a hierarchy (i.e. settings in a Texture block
- * can be overridden by settings from Scene, which owns the Texture through a hierarchy
- * such as Scene->World->MTex/Texture) can still get correctly overridden.
+ const float ctime = BKE_scene_frame_get(scene);
+ /* Keep this first. */
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
+ /* Update animated image textures for particles, modifiers, gpu, etc,
+ * call this at the start so modifiers with textures don't lag 1 frame.
*/
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
- /*...done with recursive funcs */
- }
-#endif
-
- /* clear "LIB_TAG_DOIT" flag from all materials, to prevent infinite recursion problems later
- * when trying to find materials with drivers that need evaluating [#32017]
+ BKE_image_update_frame(bmain, scene->r.cfra);
+ BKE_sound_set_cfra(scene->r.cfra);
+ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer);
+ /* Update animated cache files for modifiers.
+ *
+ * TODO(sergey): Make this a depsgraph node?
*/
- BKE_main_id_tag_idcode(bmain, ID_MA, LIB_TAG_DOIT, false);
- BKE_main_id_tag_idcode(bmain, ID_LA, LIB_TAG_DOIT, false);
-
- /* run rigidbody sim */
- /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- scene_do_rb_simulation_recursive(sce, ctime);
- }
-#endif
-
- /* BKE_object_handle_update() on all objects, groups and sets */
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (use_new_eval) {
- DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
- }
- else {
- scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
- }
-#else
- DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
-#endif
-
- /* update sound system animation (TODO, move to depsgraph) */
- BKE_sound_update_scene(bmain, sce);
-
-#ifdef WITH_LEGACY_DEPSGRAPH
- if (!use_new_eval) {
- scene_depsgraph_hack(bmain, eval_ctx, sce, sce);
- }
+ BKE_cachefile_update_frame(bmain, depsgraph, scene, ctime,
+ (((double)scene->r.frs_sec) / (double)scene->r.frs_sec_base));
+#ifdef POSE_ANIMATION_WORKAROUND
+ scene_armature_depsgraph_workaround(bmain, depsgraph);
#endif
-
- /* notify editors and python about recalc */
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST);
- BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST);
-
+ /* Update all objects: drivers, matrices, displists, etc. flags set
+ * by depgraph or manual, no layer check here, gets correct flushed.
+ */
+ DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
+ /* Update sound system animation (TODO, move to depsgraph). */
+ BKE_sound_update_scene(bmain, scene);
+ /* Notify editors and python about recalc. */
+ BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
/* Inform editors about possible changes. */
- DAG_ids_check_recalc(bmain, sce, true);
-
+ DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
/* clear recalc flags */
- DAG_ids_clear_recalc(bmain);
-
-#ifdef DETAILED_ANALYSIS_OUTPUT
- fprintf(stderr, "frame update start_time %f duration %f\n", start_time, PIL_check_seconds_timer() - start_time);
-#endif
+ DEG_ids_clear_recalc(bmain, depsgraph);
}
-/* return default layer, also used to patch old files */
-SceneRenderLayer *BKE_scene_add_render_layer(Scene *sce, const char *name)
+/** Ensures given scene/view_layer pair has a valid, up-to-date depsgraph.
+ *
+ * \warning Sets matching depsgraph as active, so should only be called from the active editing context
+ * (usually, from operators).
+ */
+void BKE_scene_view_layer_graph_evaluated_ensure(Main *bmain, Scene *scene, ViewLayer *view_layer)
{
- SceneRenderLayer *srl;
-
- if (!name)
- name = DATA_("RenderLayer");
-
- srl = MEM_callocN(sizeof(SceneRenderLayer), "new render layer");
- BLI_strncpy(srl->name, name, sizeof(srl->name));
- BLI_uniquename(&sce->r.layers, srl, DATA_("RenderLayer"), '.', offsetof(SceneRenderLayer, name), sizeof(srl->name));
- BLI_addtail(&sce->r.layers, srl);
-
- /* note, this is also in render, pipeline.c, to make layer when scenedata doesnt have it */
- srl->lay = (1 << 20) - 1;
- srl->layflag = 0x7FFF; /* solid ztra halo edge strand */
- srl->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
- srl->pass_alpha_threshold = 0.5f;
- BKE_freestyle_config_init(&srl->freestyleConfig);
-
- return srl;
-}
-
-bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer *srl)
-{
- const int act = BLI_findindex(&scene->r.layers, srl);
- Scene *sce;
-
- if (act == -1) {
- return false;
- }
- else if ( (scene->r.layers.first == scene->r.layers.last) &&
- (scene->r.layers.first == srl))
- {
- /* ensure 1 layer is kept */
- return false;
- }
-
- BKE_freestyle_config_free(&srl->freestyleConfig);
-
- if (srl->prop) {
- IDP_FreeProperty(srl->prop);
- MEM_freeN(srl->prop);
- }
-
- BLI_remlink(&scene->r.layers, srl);
- MEM_freeN(srl);
-
- scene->r.actlay = 0;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- if (sce->nodetree) {
- bNode *node;
- for (node = sce->nodetree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) {
- if (node->custom1 == act)
- node->custom1 = 0;
- else if (node->custom1 > act)
- node->custom1--;
- }
- }
- }
- }
-
- return true;
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ DEG_make_active(depsgraph);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
}
/* return default view */
@@ -2223,37 +1550,34 @@ int get_render_child_particle_number(const RenderData *r, int num, bool for_rend
}
}
-int get_render_shadow_samples(const RenderData *r, int samples)
-{
- if ((r->mode & R_SIMPLIFY) && samples > 0)
- return min_ii(r->simplify_shadowsamples, samples);
- else
- return samples;
-}
-
-float get_render_aosss_error(const RenderData *r, float error)
-{
- if (r->mode & R_SIMPLIFY)
- return ((1.0f - r->simplify_aosss) * 10.0f + 1.0f) * error;
- else
- return error;
-}
-
-/* helper function for the SETLOOPER macro */
-Base *_setlooper_base_step(Scene **sce_iter, Base *base)
+/**
+ * Helper function for the SETLOOPER and SETLOOPER_VIEW_LAYER macros
+ *
+ * It iterates over the bases of the active layer and then the bases
+ * of the active layer of the background (set) scenes recursively.
+ */
+Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base)
{
if (base && base->next) {
- /* common case, step to the next */
+ /* Common case, step to the next. */
return base->next;
}
- else if (base == NULL && (*sce_iter)->base.first) {
- /* first time looping, return the scenes first base */
- return (Base *)(*sce_iter)->base.first;
+ else if ((base == NULL) && (view_layer != NULL)) {
+ /* First time looping, return the scenes first base. */
+ /* For the first loop we should get the layer from workspace when available. */
+ if (view_layer->object_bases.first) {
+ return (Base *)view_layer->object_bases.first;
+ }
+ /* No base on this scene layer. */
+ goto next_set;
}
else {
- /* reached the end, get the next base in the set */
+next_set:
+ /* Reached the end, get the next base in the set. */
while ((*sce_iter = (*sce_iter)->set)) {
- base = (Base *)(*sce_iter)->base.first;
+ ViewLayer *view_layer_set = BKE_view_layer_default_render((*sce_iter));
+ base = (Base *)view_layer_set->object_bases.first;
+
if (base) {
return base;
}
@@ -2263,58 +1587,68 @@ Base *_setlooper_base_step(Scene **sce_iter, Base *base)
return NULL;
}
-bool BKE_scene_use_new_shading_nodes(const Scene *scene)
-{
- const RenderEngineType *type = RE_engines_find(scene->r.engine);
- return (type && type->flag & RE_USE_SHADING_NODES);
-}
-
bool BKE_scene_use_shading_nodes_custom(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
return (type && type->flag & RE_USE_SHADING_NODES_CUSTOM);
}
-bool BKE_scene_use_world_space_shading(Scene *scene)
-{
- const RenderEngineType *type = RE_engines_find(scene->r.engine);
- return ((scene->r.mode & R_USE_WS_SHADING) ||
- (type && (type->flag & RE_USE_SHADING_NODES)));
-}
-
bool BKE_scene_use_spherical_stereo(Scene *scene)
{
RenderEngineType *type = RE_engines_find(scene->r.engine);
return (type && type->flag & RE_USE_SPHERICAL_STEREO);
}
-bool BKE_scene_uses_blender_internal(const Scene *scene)
+bool BKE_scene_uses_blender_eevee(const Scene *scene)
+{
+ return STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE);
+}
+
+bool BKE_scene_uses_blender_opengl(const Scene *scene)
{
- return STREQ(scene->r.engine, RE_engine_id_BLENDER_RENDER);
+ return STREQ(scene->r.engine, RE_engine_id_BLENDER_OPENGL);
}
-bool BKE_scene_uses_blender_game(const Scene *scene)
+bool BKE_scene_uses_cycles(const Scene *scene)
{
- return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME);
+ return STREQ(scene->r.engine, RE_engine_id_CYCLES);
}
-void BKE_scene_base_flag_to_objects(struct Scene *scene)
+void BKE_scene_base_flag_to_objects(ViewLayer *view_layer)
{
- Base *base = scene->base.first;
+ Base *base = view_layer->object_bases.first;
while (base) {
- base->object->flag = base->flag;
+ BKE_scene_object_base_flag_sync_from_base(base);
base = base->next;
}
}
-void BKE_scene_base_flag_from_objects(struct Scene *scene)
+void BKE_scene_object_base_flag_sync_from_base(Base *base)
{
- Base *base = scene->base.first;
+ Object *ob = base->object;
- while (base) {
- base->flag = base->object->flag;
- base = base->next;
+ ob->flag = base->flag;
+
+ if ((base->flag & BASE_SELECTED) != 0) {
+ ob->flag |= SELECT;
+ }
+ else {
+ ob->flag &= ~SELECT;
+ }
+}
+
+void BKE_scene_object_base_flag_sync_from_object(Base *base)
+{
+ Object *ob = base->object;
+ base->flag = ob->flag;
+
+ if ((ob->flag & SELECT) != 0) {
+ base->flag |= BASE_SELECTED;
+ BLI_assert((base->flag & BASE_SELECTABLE) != 0);
+ }
+ else {
+ base->flag &= ~BASE_SELECTED;
}
}
@@ -2683,3 +2017,146 @@ int BKE_scene_multiview_num_videos_get(const RenderData *rd)
return BKE_scene_multiview_num_views_get(rd);
}
}
+
+/* Manipulation of depsgraph storage. */
+
+/* This is a key which identifies depsgraph. */
+typedef struct DepsgraphKey {
+ ViewLayer *view_layer;
+ /* TODO(sergey): Need to include window somehow (same layer might be in a
+ * different states in different windows).
+ */
+} DepsgraphKey;
+
+static unsigned int depsgraph_key_hash(const void *key_v)
+{
+ const DepsgraphKey *key = key_v;
+ unsigned int hash = BLI_ghashutil_ptrhash(key->view_layer);
+ /* TODO(sergey): Include hash from other fields in the key. */
+ return hash;
+}
+
+static bool depsgraph_key_compare(const void *key_a_v, const void *key_b_v)
+{
+ const DepsgraphKey *key_a = key_a_v;
+ const DepsgraphKey *key_b = key_b_v;
+ /* TODO(sergey): Compare rest of */
+ return !(key_a->view_layer == key_b->view_layer);
+}
+
+static void depsgraph_key_free(void *key_v)
+{
+ DepsgraphKey *key = key_v;
+ MEM_freeN(key);
+}
+
+static void depsgraph_key_value_free(void *value)
+{
+ Depsgraph *depsgraph = value;
+ DEG_graph_free(depsgraph);
+}
+
+void BKE_scene_allocate_depsgraph_hash(Scene *scene)
+{
+ scene->depsgraph_hash = BLI_ghash_new(depsgraph_key_hash,
+ depsgraph_key_compare,
+ "Scene Depsgraph Hash");
+}
+
+void BKE_scene_ensure_depsgraph_hash(Scene *scene)
+{
+ if (scene->depsgraph_hash == NULL) {
+ BKE_scene_allocate_depsgraph_hash(scene);
+ }
+}
+
+void BKE_scene_free_depsgraph_hash(Scene *scene)
+{
+ if (scene->depsgraph_hash == NULL) {
+ return;
+ }
+ BLI_ghash_free(scene->depsgraph_hash,
+ depsgraph_key_free,
+ depsgraph_key_value_free);
+}
+
+/* Query depsgraph for a specific contexts. */
+
+Depsgraph *BKE_scene_get_depsgraph(Scene *scene,
+ ViewLayer *view_layer,
+ bool allocate)
+{
+ BLI_assert(scene != NULL);
+ BLI_assert(view_layer != NULL);
+ /* Make sure hash itself exists. */
+ if (allocate) {
+ BKE_scene_ensure_depsgraph_hash(scene);
+ }
+ if (scene->depsgraph_hash == NULL) {
+ return NULL;
+ }
+ /* Either ensure item is in the hash or simply return NULL if it's not,
+ * depending on whether caller wants us to create depsgraph or not.
+ */
+ DepsgraphKey key;
+ key.view_layer = view_layer;
+ Depsgraph *depsgraph;
+ if (allocate) {
+ DepsgraphKey **key_ptr;
+ Depsgraph **depsgraph_ptr;
+ if (!BLI_ghash_ensure_p_ex(scene->depsgraph_hash,
+ &key,
+ (void ***)&key_ptr,
+ (void ***)&depsgraph_ptr))
+ {
+ *key_ptr = MEM_mallocN(sizeof(DepsgraphKey), __func__);
+ **key_ptr = key;
+ *depsgraph_ptr = DEG_graph_new(scene, view_layer, DAG_EVAL_VIEWPORT);
+ /* TODO(sergey): Would be cool to avoid string format print,
+ * but is a bit tricky because we can't know in advance whether
+ * we will ever enable debug messages for this depsgraph.
+ */
+ char name[1024];
+ BLI_snprintf(name, sizeof(name), "%s :: %s", scene->id.name, view_layer->name);
+ DEG_debug_name_set(*depsgraph_ptr, name);
+ }
+ depsgraph = *depsgraph_ptr;
+ }
+ else {
+ depsgraph = BLI_ghash_lookup(scene->depsgraph_hash, &key);
+ }
+ return depsgraph;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Scene Orientation
+ * \{ */
+
+void BKE_scene_transform_orientation_remove(
+ Scene *scene, TransformOrientation *orientation)
+{
+ const int orientation_index = BKE_scene_transform_orientation_get_index(scene, orientation);
+ if (scene->orientation_index_custom == orientation_index) {
+ /* could also use orientation_index-- */
+ scene->orientation_type = V3D_MANIP_GLOBAL;
+ scene->orientation_index_custom = -1;
+ }
+ BLI_freelinkN(&scene->transform_spaces, orientation);
+}
+
+TransformOrientation *BKE_scene_transform_orientation_find(
+ const Scene *scene, const int index)
+{
+ return BLI_findlink(&scene->transform_spaces, index);
+}
+
+/**
+ * \return the index that \a orientation has within \a scene's transform-orientation list or -1 if not found.
+ */
+int BKE_scene_transform_orientation_get_index(
+ const Scene *scene, const TransformOrientation *orientation)
+{
+ return BLI_findindex(&scene->transform_spaces, orientation);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 3c615221564..84962e9b03f 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -39,19 +39,21 @@
#include "MEM_guardedalloc.h"
-#include "GPU_compositing.h"
-
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_workspace_types.h"
+#include "BLI_math_vector.h"
#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
#include "BLI_rect.h"
+#include "BLI_utildefines.h"
+#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
/* ************ Spacetype/regiontype handling ************** */
@@ -72,6 +74,8 @@ static void spacetype_free(SpaceType *st)
if (pt->ext.free) {
pt->ext.free(pt->ext.data);
}
+
+ BLI_freelistN(&pt->children);
}
for (ht = art->headertypes.first; ht; ht = ht->next) {
@@ -85,8 +89,6 @@ static void spacetype_free(SpaceType *st)
}
BLI_freelistN(&st->regiontypes);
- BLI_freelistN(&st->toolshelf);
-
}
void BKE_spacetypes_free(void)
@@ -184,10 +186,35 @@ void BKE_spacedata_freelist(ListBase *lb)
BLI_freelistN(lb);
}
+static void panel_list_copy(ListBase *newlb, const ListBase *lb)
+{
+ BLI_listbase_clear(newlb);
+ BLI_duplicatelist(newlb, lb);
+
+ /* copy panel pointers */
+ Panel *newpa = newlb->first;
+ Panel *pa = lb->first;
+ for (; newpa; newpa = newpa->next, pa = pa->next) {
+ newpa->activedata = NULL;
+
+ Panel *newpatab = newlb->first;
+ Panel *patab = lb->first;
+ while (newpatab) {
+ if (newpa->paneltab == patab) {
+ newpa->paneltab = newpatab;
+ break;
+ }
+ newpatab = newpatab->next;
+ patab = patab->next;
+ }
+
+ panel_list_copy(&newpa->children, &pa->children);
+ }
+}
+
ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
{
ARegion *newar = MEM_dupallocN(ar);
- Panel *pa, *newpa, *patab;
newar->prev = newar->next = NULL;
BLI_listbase_clear(&newar->handlers);
@@ -195,9 +222,11 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
BLI_listbase_clear(&newar->panels_category);
BLI_listbase_clear(&newar->panels_category_active);
BLI_listbase_clear(&newar->ui_lists);
- newar->swinid = 0;
+ newar->visible = 0;
+ newar->gizmo_map = NULL;
newar->regiontimer = NULL;
newar->headerstr = NULL;
+ newar->draw_buffer = NULL;
/* use optional regiondata callback */
if (ar->regiondata) {
@@ -217,26 +246,11 @@ ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
if (ar->v2d.tab_offset)
newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset);
- BLI_listbase_clear(&newar->panels);
- BLI_duplicatelist(&newar->panels, &ar->panels);
+ panel_list_copy(&newar->panels, &ar->panels);
BLI_listbase_clear(&newar->ui_previews);
BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews);
- /* copy panel pointers */
- for (newpa = newar->panels.first; newpa; newpa = newpa->next) {
- patab = newar->panels.first;
- pa = ar->panels.first;
- while (patab) {
- if (newpa->paneltab == pa) {
- newpa->paneltab = patab;
- break;
- }
- patab = patab->next;
- pa = pa->next;
- }
- }
-
return newar;
}
@@ -310,6 +324,57 @@ void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID
}
}
+/**
+ * Avoid bad-level calls to #WM_gizmomap_tag_refresh.
+ */
+static void (*region_refresh_tag_gizmomap_callback)(struct wmGizmoMap *) = NULL;
+
+void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizmoMap *))
+{
+ region_refresh_tag_gizmomap_callback = callback;
+}
+
+void BKE_screen_gizmo_tag_refresh(struct bScreen *sc)
+{
+ if (region_refresh_tag_gizmomap_callback == NULL) {
+ return;
+ }
+
+ ScrArea *sa;
+ ARegion *ar;
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->gizmo_map != NULL) {
+ region_refresh_tag_gizmomap_callback(ar->gizmo_map);
+ }
+ }
+ }
+}
+
+/**
+ * Avoid bad-level calls to #WM_gizmomap_delete.
+ */
+static void (*region_free_gizmomap_callback)(struct wmGizmoMap *) = NULL;
+
+void BKE_region_callback_free_gizmomap_set(void (*callback)(struct wmGizmoMap *))
+{
+ region_free_gizmomap_callback = callback;
+}
+
+void BKE_area_region_panels_free(ListBase *lb)
+{
+ Panel *pa, *pa_next;
+ for (pa = lb->first; pa; pa = pa_next) {
+ pa_next = pa->next;
+ if (pa->activedata) {
+ MEM_freeN(pa->activedata);
+ }
+ BKE_area_region_panels_free(&pa->children);
+ }
+
+ BLI_freelistN(lb);
+}
+
/* not region itself */
void BKE_area_region_free(SpaceType *st, ARegion *ar)
{
@@ -332,16 +397,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
ar->v2d.tab_offset = NULL;
}
- if (!BLI_listbase_is_empty(&ar->panels)) {
- Panel *pa, *pa_next;
- for (pa = ar->panels.first; pa; pa = pa_next) {
- pa_next = pa->next;
- if (pa->activedata) {
- MEM_freeN(pa->activedata);
- }
- MEM_freeN(pa);
- }
- }
+ BKE_area_region_panels_free(&ar->panels);
for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) {
if (uilst->dyn_data) {
@@ -359,6 +415,11 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar)
MEM_freeN(uilst->properties);
}
}
+
+ if (ar->gizmo_map != NULL) {
+ region_free_gizmomap_callback(ar->gizmo_map);
+ }
+
BLI_freelistN(&ar->ui_lists);
BLI_freelistN(&ar->ui_previews);
BLI_freelistN(&ar->panels_category);
@@ -374,6 +435,7 @@ void BKE_screen_area_free(ScrArea *sa)
for (ar = sa->regionbase.first; ar; ar = ar->next)
BKE_area_region_free(st, ar);
+ MEM_SAFE_FREE(sa->global);
BLI_freelistN(&sa->regionbase);
BKE_spacedata_freelist(&sa->spacedata);
@@ -381,10 +443,21 @@ void BKE_screen_area_free(ScrArea *sa)
BLI_freelistN(&sa->actionzones);
}
+void BKE_screen_area_map_free(ScrAreaMap *area_map)
+{
+ for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) {
+ area_next = area->next;
+ BKE_screen_area_free(area);
+ }
+
+ BLI_freelistN(&area_map->vertbase);
+ BLI_freelistN(&area_map->edgebase);
+ BLI_freelistN(&area_map->areabase);
+}
+
/** Free (or release) any data used by this screen (does not free the screen itself). */
void BKE_screen_free(bScreen *sc)
{
- ScrArea *sa, *san;
ARegion *ar;
/* No animdata here. */
@@ -394,36 +467,179 @@ void BKE_screen_free(bScreen *sc)
BLI_freelistN(&sc->regionbase);
- for (sa = sc->areabase.first; sa; sa = san) {
- san = sa->next;
- BKE_screen_area_free(sa);
- }
+ BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(sc));
- BLI_freelistN(&sc->vertbase);
- BLI_freelistN(&sc->edgebase);
- BLI_freelistN(&sc->areabase);
+ BKE_previewimg_free(&sc->preview);
/* Region and timer are freed by the window manager. */
MEM_SAFE_FREE(sc->tool_tip);
}
-/* for depsgraph */
-unsigned int BKE_screen_visible_layers(bScreen *screen, Scene *scene)
+/* ***************** Screen edges & verts ***************** */
+
+ScrEdge *BKE_screen_find_edge(bScreen *sc, ScrVert *v1, ScrVert *v2)
+{
+ ScrEdge *se;
+
+ BKE_screen_sort_scrvert(&v1, &v2);
+ for (se = sc->edgebase.first; se; se = se->next) {
+ if (se->v1 == v1 && se->v2 == v2) {
+ return se;
+ }
+ }
+
+ return NULL;
+}
+
+void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
+{
+ ScrVert *tmp;
+
+ if (*v1 > *v2) {
+ tmp = *v1;
+ *v1 = *v2;
+ *v2 = tmp;
+ }
+}
+
+void BKE_screen_remove_double_scrverts(bScreen *sc)
{
+ ScrVert *v1, *verg;
+ ScrEdge *se;
ScrArea *sa;
- unsigned int layer = 0;
- if (screen) {
- /* get all used view3d layers */
- for (sa = screen->areabase.first; sa; sa = sa->next)
- if (sa->spacetype == SPACE_VIEW3D)
- layer |= ((View3D *)sa->spacedata.first)->lay;
+ verg = sc->vertbase.first;
+ while (verg) {
+ if (verg->newv == NULL) { /* !!! */
+ v1 = verg->next;
+ while (v1) {
+ if (v1->newv == NULL) { /* !?! */
+ if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
+ /* printf("doublevert\n"); */
+ v1->newv = verg;
+ }
+ }
+ v1 = v1->next;
+ }
+ }
+ verg = verg->next;
+ }
+
+ /* replace pointers in edges and faces */
+ se = sc->edgebase.first;
+ while (se) {
+ if (se->v1->newv) se->v1 = se->v1->newv;
+ if (se->v2->newv) se->v2 = se->v2->newv;
+ /* edges changed: so.... */
+ BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
+ se = se->next;
+ }
+ sa = sc->areabase.first;
+ while (sa) {
+ if (sa->v1->newv) sa->v1 = sa->v1->newv;
+ if (sa->v2->newv) sa->v2 = sa->v2->newv;
+ if (sa->v3->newv) sa->v3 = sa->v3->newv;
+ if (sa->v4->newv) sa->v4 = sa->v4->newv;
+ sa = sa->next;
+ }
+
+ /* remove */
+ verg = sc->vertbase.first;
+ while (verg) {
+ v1 = verg->next;
+ if (verg->newv) {
+ BLI_remlink(&sc->vertbase, verg);
+ MEM_freeN(verg);
+ }
+ verg = v1;
+ }
+
+}
+
+void BKE_screen_remove_double_scredges(bScreen *sc)
+{
+ ScrEdge *verg, *se, *sn;
+
+ /* compare */
+ verg = sc->edgebase.first;
+ while (verg) {
+ se = verg->next;
+ while (se) {
+ sn = se->next;
+ if (verg->v1 == se->v1 && verg->v2 == se->v2) {
+ BLI_remlink(&sc->edgebase, se);
+ MEM_freeN(se);
+ }
+ se = sn;
+ }
+ verg = verg->next;
}
+}
+
+void BKE_screen_remove_unused_scredges(bScreen *sc)
+{
+ ScrEdge *se, *sen;
+ ScrArea *sa;
+ int a = 0;
+
+ /* sets flags when edge is used in area */
+ sa = sc->areabase.first;
+ while (sa) {
+ se = BKE_screen_find_edge(sc, sa->v1, sa->v2);
+ if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a);
+ else se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
+ if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a);
+ else se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v3, sa->v4);
+ if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a);
+ else se->flag = 1;
+ se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
+ if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a);
+ else se->flag = 1;
+ sa = sa->next;
+ a++;
+ }
+ se = sc->edgebase.first;
+ while (se) {
+ sen = se->next;
+ if (se->flag == 0) {
+ BLI_remlink(&sc->edgebase, se);
+ MEM_freeN(se);
+ }
+ else {
+ se->flag = 0;
+ }
+ se = sen;
+ }
+}
+
+void BKE_screen_remove_unused_scrverts(bScreen *sc)
+{
+ ScrVert *sv, *svn;
+ ScrEdge *se;
- if (!layer)
- return scene->lay;
+ /* we assume edges are ok */
- return layer;
+ se = sc->edgebase.first;
+ while (se) {
+ se->v1->flag = 1;
+ se->v2->flag = 1;
+ se = se->next;
+ }
+
+ sv = sc->vertbase.first;
+ while (sv) {
+ svn = sv->next;
+ if (sv->flag == 0) {
+ BLI_remlink(&sc->vertbase, sv);
+ MEM_freeN(sv);
+ }
+ else {
+ sv->flag = 0;
+ }
+ sv = svn;
+ }
}
/* ***************** Utilities ********************** */
@@ -514,71 +730,26 @@ ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short
return big;
}
-ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
+ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap, const int spacetype, int x, int y)
{
- ScrArea *sa, *sa_found = NULL;
-
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ for (ScrArea *sa = areamap->areabase.first; sa; sa = sa->next) {
if (BLI_rcti_isect_pt(&sa->totrct, x, y)) {
if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
- sa_found = sa;
+ return sa;
}
break;
}
}
- return sa_found;
-}
-
-
-/**
- * Utility function to get the active layer to use when adding new objects.
- */
-unsigned int BKE_screen_view3d_layer_active_ex(const View3D *v3d, const Scene *scene, bool use_localvd)
-{
- unsigned int lay;
- if ((v3d == NULL) || (v3d->scenelock && !v3d->localvd)) {
- lay = scene->layact;
- }
- else {
- lay = v3d->layact;
- }
-
- if (use_localvd) {
- if (v3d && v3d->localvd) {
- lay |= v3d->lay;
- }
- }
-
- return lay;
-}
-unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const struct Scene *scene)
-{
- return BKE_screen_view3d_layer_active_ex(v3d, scene, true);
+ return NULL;
}
-
-/**
- * Accumulate all visible layers on this screen.
- */
-unsigned int BKE_screen_view3d_layer_all(const bScreen *sc)
+ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
{
- const ScrArea *sa;
- unsigned int lay = 0;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
- lay |= v3d->lay;
- }
- }
-
- return lay;
+ return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(sc), spacetype, x, y);
}
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
{
- int bit;
-
if (v3d->scenelock && v3d->localvd == NULL) {
- v3d->lay = scene->lay;
v3d->camera = scene->camera;
if (v3d->camera == NULL) {
@@ -592,19 +763,10 @@ void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
}
}
}
-
- if ((v3d->lay & v3d->layact) == 0) {
- for (bit = 0; bit < 32; bit++) {
- if (v3d->lay & (1u << bit)) {
- v3d->layact = (1u << bit);
- break;
- }
- }
- }
}
}
-void BKE_screen_view3d_scene_sync(bScreen *sc)
+void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
{
/* are there cameras in the views that are not in the scene? */
ScrArea *sa;
@@ -613,59 +775,27 @@ 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)
+void BKE_screen_view3d_shading_init(View3DShading *shading)
{
- bScreen *sc;
- ScrArea *sa;
- SpaceLink *sl;
+ memset(shading, 0, sizeof(*shading));
- /* from scene copy to the other views */
- for (sc = screen_lb->first; sc; sc = sc->id.next) {
- if (sc->scene != scene)
- continue;
-
- for (sa = sc->areabase.first; sa; sa = sa->next)
- for (sl = sa->spacedata.first; sl; sl = sl->next)
- if (sl->spacetype == SPACE_VIEW3D)
- BKE_screen_view3d_sync((View3D *)sl, scene);
- }
-}
-
-void BKE_screen_view3d_twmode_remove(View3D *v3d, const int i)
-{
- const int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
- if (selected_index == i) {
- v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
- }
- else if (selected_index > i) {
- v3d->twmode--;
- }
-}
-
-void BKE_screen_view3d_main_twmode_remove(ListBase *screen_lb, Scene *scene, const int i)
-{
- bScreen *sc;
-
- for (sc = screen_lb->first; sc; sc = sc->id.next) {
- if (sc->scene == scene) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *)sl;
- BKE_screen_view3d_twmode_remove(v3d, i);
- }
- }
- }
- }
- }
+ shading->type = OB_SOLID;
+ shading->prev_type = OB_SOLID;
+ shading->flag = V3D_SHADING_SPECULAR_HIGHLIGHT | V3D_SHADING_XRAY_WIREFRAME;
+ shading->light = V3D_LIGHTING_STUDIO;
+ shading->shadow_intensity = 0.5f;
+ shading->xray_alpha = 0.5f;
+ shading->xray_alpha_wire = 0.5f;
+ shading->cavity_valley_factor = 1.0f;
+ shading->cavity_ridge_factor = 1.0f;
+ copy_v3_fl(shading->single_color, 0.8f);
+ copy_v3_fl(shading->background_color, 0.05f);
}
/* magic zoom calculation, no idea what
@@ -686,25 +816,12 @@ float BKE_screen_view3d_zoom_from_fac(float zoomfac)
return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
}
-void BKE_screen_gpu_fx_validate(GPUFXSettings *fx_settings)
+bool BKE_screen_is_fullscreen_area(const bScreen *screen)
{
- /* currently we use DOF from the camera _only_,
- * so we never allocate this, only copy from the Camera */
-#if 0
- if ((fx_settings->dof == NULL) &&
- (fx_settings->fx_flag & GPU_FX_FLAG_DOF))
- {
- GPUDOFSettings *fx_dof;
- fx_dof = fx_settings->dof = MEM_callocN(sizeof(GPUDOFSettings), __func__);
- }
-#endif
-
- if ((fx_settings->ssao == NULL) &&
- (fx_settings->fx_flag & GPU_FX_FLAG_SSAO))
- {
- GPUSSAOSettings *fx_ssao;
- fx_ssao = fx_settings->ssao = MEM_callocN(sizeof(GPUSSAOSettings), __func__);
+ return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
+}
- GPU_fx_compositor_init_ssao_settings(fx_ssao);
- }
+bool BKE_screen_is_used(const bScreen *screen)
+{
+ return (screen->winid != 0);
}
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 08952113fce..ba2d2ef0d46 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -1767,76 +1767,6 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
if (output != output) output = 1;
if (wipe->forward) output = 1 - output;
break;
- /* BOX WIPE IS NOT WORKING YET */
- /* case DO_CROSS_WIPE: */
- /* BOX WIPE IS NOT WORKING YET */
-#if 0
- case DO_BOX_WIPE:
- if (!wipe->forward) {
- facf0 = 1.0f - facf0; /* Go the other direction */
- }
-
- width = (int)(wipe->edgeWidth * ((xo + yo) / 2.0));
- hwidth = (float)width / 2.0;
- if (angle == 0) angle = 0.000001;
- b1 = posy / 2 - (-angle) * posx / 2;
- b3 = (yo - posy / 2) - (-angle) * (xo - posx / 2);
- b2 = y - (-angle) * x;
-
- hyp = abs(angle * x + y + (-posy / 2 - angle * posx / 2)) * wipezone->pythangle;
- hyp2 = abs(angle * x + y + (-(yo - posy / 2) - angle * (xo - posx / 2))) * wipezone->pythangle;
-
- temp1 = xo * (1 - facf0 / 2) - xo * facf0 / 2;
- temp2 = yo * (1 - facf0 / 2) - yo * facf0 / 2;
- pointdist = hypot(temp1, temp2);
-
- if (b2 < b1 && b2 < b3) {
- if (hwidth < pointdist)
- output = in_band(hwidth, hyp, 0, 1);
- }
- else if (b2 > b1 && b2 > b3) {
- if (hwidth < pointdist)
- output = in_band(hwidth, hyp2, 0, 1);
- }
- else {
- if (hyp < hwidth && hyp2 > hwidth)
- output = in_band(hwidth, hyp, 1, 1);
- else if (hyp > hwidth && hyp2 < hwidth)
- output = in_band(hwidth, hyp2, 1, 1);
- else
- output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
- }
-
- if (!wipe->forward) {
- facf0 = 1.0f - facf0; /* Go the other direction */
- }
- angle = -1 / angle;
- b1 = posy / 2 - (-angle) * posx / 2;
- b3 = (yo - posy / 2) - (-angle) * (xo - posx / 2);
- b2 = y - (-angle) * x;
-
- hyp = abs(angle * x + y + (-posy / 2 - angle * posx / 2)) * wipezone->pythangle;
- hyp2 = abs(angle * x + y + (-(yo - posy / 2) - angle * (xo - posx / 2))) * wipezone->pythangle;
-
- if (b2 < b1 && b2 < b3) {
- if (hwidth < pointdist)
- output *= in_band(hwidth, hyp, 0, 1);
- }
- else if (b2 > b1 && b2 > b3) {
- if (hwidth < pointdist)
- output *= in_band(hwidth, hyp2, 0, 1);
- }
- else {
- if (hyp < hwidth && hyp2 > hwidth)
- output *= in_band(hwidth, hyp, 1, 1);
- else if (hyp > hwidth && hyp2 < hwidth)
- output *= in_band(hwidth, hyp2, 1, 1);
- else
- output *= in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
- }
-
- break;
-#endif
case DO_IRIS_WIPE:
if (xo > yo) yo = xo;
else xo = yo;
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index c2a96d4f1ff..0d506effae6 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -63,9 +63,9 @@
#include "BLT_translation.h"
#include "BKE_animsys.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_sequencer.h"
#include "BKE_movieclip.h"
@@ -75,6 +75,9 @@
#include "BKE_library.h"
#include "BKE_idprop.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RNA_access.h"
#include "RE_pipeline.h"
@@ -89,8 +92,10 @@
#include "BKE_context.h"
#include "BKE_sound.h"
+#include "RE_engine.h"
+
#ifdef WITH_AUDASPACE
-# include AUD_SPECIAL_H
+# include <AUD_Special.h>
#endif
/* mutable state for sequencer */
@@ -588,17 +593,17 @@ void BKE_sequencer_pixel_from_sequencer_space_v4(struct Scene *scene, float pixe
/*********************** sequencer pipeline functions *************************/
void BKE_sequencer_new_render_data(
- EvaluationContext *eval_ctx,
- Main *bmain, Scene *scene, int rectx, int recty,
- int preview_render_size,
+ Main *bmain, struct Depsgraph *depsgraph, Scene *scene, int rectx, int recty,
+ int preview_render_size, int for_render,
SeqRenderData *r_context)
{
- r_context->eval_ctx = eval_ctx;
r_context->bmain = bmain;
+ r_context->depsgraph = depsgraph;
r_context->scene = scene;
r_context->rectx = rectx;
r_context->recty = recty;
r_context->preview_render_size = preview_render_size;
+ r_context->for_render = for_render;
r_context->motion_blur_samples = 0;
r_context->motion_blur_shutter = 0;
r_context->skip_cache = false;
@@ -1458,6 +1463,7 @@ typedef struct SeqIndexBuildContext {
int view_id;
Main *bmain;
+ Depsgraph *depsgraph;
Scene *scene;
Sequence *seq, *orig_seq;
} SeqIndexBuildContext;
@@ -1590,12 +1596,8 @@ static void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
}
if (sanim->anim) {
-#if 0
- seq_anim_add_suffix(scene, sanim->anim, i);
-#else
/* we already have the suffix */
IMB_suffix_anim(sanim->anim, suffix);
-#endif
}
else {
if (openfile) {
@@ -1946,7 +1948,9 @@ static int seq_proxy_context_count(Sequence *seq, Scene *scene)
return num_views;
}
-void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list, ListBase *queue)
+void BKE_sequencer_proxy_rebuild_context(
+ Main *bmain, Depsgraph *depsgraph, Scene *scene,
+ Sequence *seq, struct GSet *file_list, ListBase *queue)
{
SeqIndexBuildContext *context;
Sequence *nseq;
@@ -1978,6 +1982,7 @@ void BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *se
context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
context->bmain = bmain;
+ context->depsgraph = depsgraph;
context->scene = scene;
context->orig_seq = seq;
context->seq = nseq;
@@ -2031,9 +2036,10 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
/* fail safe code */
BKE_sequencer_new_render_data(
- bmain->eval_ctx, bmain, context->scene,
+ bmain, context->depsgraph, context->scene,
(scene->r.size * (float) scene->r.xsch) / 100.0f + 0.5f,
(scene->r.size * (float) scene->r.ysch) / 100.0f + 0.5f, 100,
+ false,
&render_context);
render_context.skip_cache = true;
@@ -2753,17 +2759,12 @@ static ImBuf *seq_render_effect_strip_impl(
if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
sh.get_default_fac(seq, cfra, &fac, &facf);
-
- if ((scene->r.mode & R_FIELDS) == 0)
- facf = fac;
+ facf = fac;
}
else {
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
if (fcu) {
fac = facf = evaluate_fcurve(fcu, cfra);
- if (scene->r.mode & R_FIELDS) {
- facf = evaluate_fcurve(fcu, cfra + 0.5f);
- }
}
else {
fac = facf = seq->effect_fader;
@@ -3131,7 +3132,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr
/* anim-data */
adt = BKE_animdata_from_id(&mask->id);
- BKE_animsys_evaluate_animdata(context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM);
+ BKE_animsys_evaluate_animdata(context->depsgraph, context->scene, &mask_temp->id, adt, nr, ADT_RECALC_ANIM);
maskbuf = MEM_mallocN(sizeof(float) * context->rectx * context->recty, __func__);
@@ -3268,6 +3269,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
// have_seq = (scene->r.scemode & R_DOSEQ) && scene->ed && scene->ed->seqbase.first); /* UNUSED */
have_comp = (scene->r.scemode & R_DOCOMP) && scene->use_nodes && scene->nodetree;
+ /* Get view layer for the strip. */
+ ViewLayer *view_layer = BKE_view_layer_default_render(scene);
+ /* Depsgraph will be NULL when doing rendering. */
+ Depsgraph *depsgraph = NULL;
+
orig_data.scemode = scene->r.scemode;
orig_data.cfra = scene->r.cfra;
orig_data.subframe = scene->r.subframe;
@@ -3323,12 +3329,16 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
context->scene->r.seq_prev_type = 3 /* == OB_SOLID */;
/* opengl offscreen render */
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
+ depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
ibuf = sequencer_view3d_cb(
/* set for OpenGL render (NULL when scrubbing) */
- context->bmain, scene, camera, width, height, IB_rect, draw_flags, context->scene->r.seq_prev_type,
+ depsgraph, scene,
+ context->scene->r.seq_prev_type,
+ camera, width, height, IB_rect,
+ draw_flags,
scene->r.alphamode, context->gpu_samples, viewname,
- context->gpu_fx, context->gpu_offscreen, err_out);
+ context->gpu_offscreen, err_out);
if (ibuf == NULL) {
fprintf(stderr, "seq_render_scene_strip failed to get opengl buffer: %s\n", err_out);
}
@@ -3349,12 +3359,11 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
* When rendering from command line renderer is called from main thread, in this
* case it's always safe to render scene here
*/
- if (!is_thread_main || is_rendering == false || is_background || context->eval_ctx->mode == DAG_EVAL_RENDER) {
+ if (!is_thread_main || is_rendering == false || is_background || context->for_render) {
if (re == NULL)
re = RE_NewSceneRender(scene);
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
- RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false);
+ RE_BlenderFrame(re, context->bmain, scene, view_layer, camera, frame, false);
/* restore previous state after it was toggled on & off by RE_BlenderFrame */
G.is_rendering = is_rendering;
@@ -3412,8 +3421,8 @@ finally:
scene->r.cfra = orig_data.cfra;
scene->r.subframe = orig_data.subframe;
- if (is_frame_update) {
- BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay);
+ if (is_frame_update && (depsgraph != NULL)) {
+ BKE_scene_graph_update_for_newframe(depsgraph, context->bmain);
}
#ifdef DURIAN_CAMERA_SWITCH
@@ -3503,7 +3512,7 @@ static ImBuf *do_render_strip_uncached(
ibuf = seq_render_scene_strip(context, seq, nr, cfra);
/* Scene strips update all animation, so we need to restore original state.*/
- BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra);
+ BKE_animsys_evaluate_all_animation(context->bmain, context->depsgraph, context->scene, cfra);
copy_to_ibuf_still(context, seq, nr, ibuf);
}
@@ -5240,11 +5249,6 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
if (sound->playback_handle == NULL) {
BKE_libblock_free(bmain, sound);
-#if 0
- if (op)
- BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
-#endif
-
return NULL;
}
@@ -5252,10 +5256,6 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
if (info.specs.channels == AUD_CHANNELS_INVALID) {
BKE_libblock_free(bmain, sound);
-#if 0
- if (op)
- BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
-#endif
return NULL;
}
diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c
new file mode 100644
index 00000000000..f19b450dece
--- /dev/null
+++ b/source/blender/blenkernel/intern/shader_fx.c
@@ -0,0 +1,245 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018, Blender Foundation
+ * This is a new part of Blender
+ *
+ * Contributor(s): Antonio Vazquez
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/shader_fx.c
+ * \ingroup bke
+ */
+
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+#include "BLI_string_utils.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_shader_fx_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_gpencil.h"
+#include "BKE_shader_fx.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "FX_shader_types.h"
+
+static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = { NULL };
+
+/* *************************************************** */
+/* Methods - Evaluation Loops, etc. */
+
+/* check if exist grease pencil effects */
+bool BKE_shaderfx_has_gpencil(Object *ob)
+{
+ ShaderFxData *fx;
+ for (fx = ob->shader_fx.first; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ if (fxi->type == eShaderFxType_GpencilType) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void BKE_shaderfx_init(void)
+{
+ /* Initialize shaders */
+ shaderfx_type_init(shader_fx_types); /* FX_shader_util.c */
+}
+
+ShaderFxData *BKE_shaderfx_new(int type)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+ ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name);
+
+ /* note, this name must be made unique later */
+ BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name));
+
+ fx->type = type;
+ fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded;
+ fx->flag = eShaderFxFlag_StaticOverride_Local;
+
+ if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode)
+ fx->mode |= eShaderFxMode_Editmode;
+
+ if (fxi->initData) fxi->initData(fx);
+
+ return fx;
+}
+
+static void shaderfx_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_min(id);
+ }
+}
+
+void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(fx, NULL, shaderfx_free_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(fx, NULL, (ShaderFxObjectWalkFunc)shaderfx_free_data_id_us_cb, NULL);
+ }
+ }
+
+ if (fxi->freeData) fxi->freeData(fx);
+ if (fx->error) MEM_freeN(fx->error);
+
+ MEM_freeN(fx);
+}
+
+void BKE_shaderfx_free(ShaderFxData *fx)
+{
+ BKE_shaderfx_free_ex(fx, 0);
+}
+
+/* check unique name */
+bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx)
+{
+ if (shaders && fx) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+ return BLI_uniquename(shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name));
+ }
+ return false;
+}
+
+bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ return fxi->dependsOnTime && fxi->dependsOnTime(fx);
+}
+
+const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type)
+{
+ /* type unsigned, no need to check < 0 */
+ if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') {
+ return shader_fx_types[type];
+ }
+ else {
+ return NULL;
+ }
+}
+
+void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type);
+
+ /* fx_dst may have already be fully initialized with some extra allocated data,
+ * we need to free it now to avoid memleak. */
+ if (fxi->freeData) {
+ fxi->freeData(fx_dst);
+ }
+
+ const size_t data_size = sizeof(ShaderFxData);
+ const char *fx_src_data = ((const char *)fx_src) + data_size;
+ char *fx_dst_data = ((char *)fx_dst) + data_size;
+ BLI_assert(data_size <= (size_t)fxi->struct_size);
+ memcpy(fx_dst_data, fx_src_data, (size_t)fxi->struct_size - data_size);
+}
+
+static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
+{
+ ID *id = *idpoin;
+ if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
+ id_us_plus(id);
+ }
+}
+
+void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag)
+{
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ target->mode = fx->mode;
+ target->flag = fx->flag;
+
+ if (fxi->copyData) {
+ fxi->copyData(fx, target);
+ }
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ if (fxi->foreachIDLink) {
+ fxi->foreachIDLink(target, NULL, shaderfx_copy_data_id_us_cb, NULL);
+ }
+ else if (fxi->foreachObjectLink) {
+ fxi->foreachObjectLink(target, NULL, (ShaderFxObjectWalkFunc)shaderfx_copy_data_id_us_cb, NULL);
+ }
+ }
+}
+
+void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target)
+{
+ BKE_shaderfx_copyData_ex(fx, target, 0);
+}
+
+ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+
+ for (; fx; fx = fx->next)
+ if (fx->type == type)
+ break;
+
+ return fx;
+}
+
+void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData)
+{
+ ShaderFxData *fx = ob->shader_fx.first;
+
+ for (; fx; fx = fx->next) {
+ const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type);
+
+ if (fxi->foreachIDLink) fxi->foreachIDLink(fx, ob, walk, userData);
+ else if (fxi->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ ShaderFxObjectWalkFunc fp = (ShaderFxObjectWalkFunc)walk;
+ fxi->foreachObjectLink(fx, ob, fp, userData);
+ }
+ }
+}
+
+ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name)
+{
+ return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name));
+}
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 13a82490895..4ba43b1a26f 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -45,15 +45,22 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_task.h"
+#include "BLI_math_solvers.h"
#include "BKE_shrinkwrap.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_DerivedMesh.h"
#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h" /* for OMP limits. */
#include "BKE_subsurf.h"
+#include "BKE_mesh_runtime.h"
+
+#include "MEM_guardedalloc.h"
#include "BLI_strict_flags.h"
@@ -67,20 +74,262 @@
/* Util macros */
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
+typedef struct ShrinkwrapCalcData {
+ ShrinkwrapModifierData *smd; //shrinkwrap modifier data
+
+ struct Object *ob; //object we are applying shrinkwrap to
+
+ struct MVert *vert; //Array of verts being projected (to fetch normals or other data)
+ float(*vertexCos)[3]; //vertexs being shrinkwraped
+ int numVerts;
+
+ struct MDeformVert *dvert; //Pointer to mdeform array
+ int vgroup; //Vertex group num
+ bool invert_vgroup; /* invert vertex group influence */
+
+ struct Mesh *target; //mesh we are shrinking to
+ struct SpaceTransform local2target; //transform to move between local and target space
+ struct ShrinkwrapTreeData *tree; // mesh BVH tree data
+
+ float keepDist; //Distance to keep above target surface (units are in local space)
+
+} ShrinkwrapCalcData;
+
typedef struct ShrinkwrapCalcCBData {
ShrinkwrapCalcData *calc;
- void *treeData;
- void *auxData;
- BVHTree *targ_tree;
- BVHTree *aux_tree;
- void *targ_callback;
- void *aux_callback;
+ ShrinkwrapTreeData *tree;
+ ShrinkwrapTreeData *aux_tree;
float *proj_axis;
SpaceTransform *local2aux;
} ShrinkwrapCalcCBData;
+
+/* Checks if the modifier needs target normals with these settings. */
+bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
+{
+ return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
+ (shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX && shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
+}
+
+/* Initializes the mesh data structure from the given mesh and settings. */
+bool BKE_shrinkwrap_init_tree(ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
+{
+ memset(data, 0, sizeof(*data));
+
+ if (!mesh || mesh->totvert <= 0) {
+ return false;
+ }
+
+ data->mesh = mesh;
+
+ if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
+ data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2);
+
+ return data->bvh != NULL;
+ }
+ else {
+ if (mesh->totpoly <= 0) {
+ return false;
+ }
+
+ data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_LOOPTRI, 4);
+
+ if (data->bvh == NULL) {
+ return false;
+ }
+
+ if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
+ if ((mesh->flag & ME_AUTOSMOOTH) != 0) {
+ data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
+ }
+ }
+
+ if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ data->boundary = mesh->runtime.shrinkwrap_data;
+ }
+
+ return true;
+ }
+}
+
+/* Frees the tree data if necessary. */
+void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
+{
+ free_bvhtree_from_mesh(&data->treeData);
+}
+
+/* Free boundary data for target project */
+void BKE_shrinkwrap_discard_boundary_data(struct Mesh *mesh)
+{
+ struct ShrinkwrapBoundaryData *data = mesh->runtime.shrinkwrap_data;
+
+ if (data != NULL) {
+ MEM_freeN((void *)data->edge_is_boundary);
+ MEM_freeN((void *)data->looptri_has_boundary);
+ MEM_freeN((void *)data->vert_boundary_id);
+ MEM_freeN((void *)data->boundary_verts);
+
+ MEM_freeN(data);
+ }
+
+ mesh->runtime.shrinkwrap_data = NULL;
+}
+
+/* Accumulate edge for average boundary edge direction. */
+static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata, signed char *status, int index, const float edge_dir[3], signed char side)
+{
+ BLI_assert(index >= 0);
+ float *direction = vdata[index].direction;
+
+ /* Invert the direction vector if either:
+ * - This is the second edge and both edges have the vertex as start or end.
+ * - For third and above, if it points in the wrong direction.
+ */
+ if (status[index] >= 0 ? status[index] == side : dot_v3v3(direction, edge_dir) < 0) {
+ sub_v3_v3(direction, edge_dir);
+ }
+ else {
+ add_v3_v3(direction, edge_dir);
+ }
+
+ status[index] = (status[index] == 0) ? side : -1;
+}
+
+static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(struct Mesh *mesh)
+{
+ const MLoop *mloop = mesh->mloop;
+ const MEdge *medge = mesh->medge;
+ const MVert *mvert = mesh->mvert;
+
+ /* Count faces per edge (up to 2). */
+ char *edge_mode = MEM_calloc_arrayN((size_t)mesh->totedge, sizeof(char), __func__);
+
+ for (int i = 0; i < mesh->totloop; i++) {
+ unsigned int eidx = mloop[i].e;
+
+ if (edge_mode[eidx] < 2) {
+ edge_mode[eidx]++;
+ }
+ }
+
+ /* Build the boundary edge bitmask. */
+ BLI_bitmap *edge_is_boundary = BLI_BITMAP_NEW(mesh->totedge, "ShrinkwrapBoundaryData::edge_is_boundary");
+ unsigned int num_boundary_edges = 0;
+
+ for (int i = 0; i < mesh->totedge; i++) {
+ edge_mode[i] = (edge_mode[i] == 1);
+
+ if (edge_mode[i]) {
+ BLI_BITMAP_ENABLE(edge_is_boundary, i);
+ num_boundary_edges++;
+ }
+ }
+
+ /* If no boundary, return NULL. */
+ if (num_boundary_edges == 0) {
+ MEM_freeN(edge_is_boundary);
+ MEM_freeN(edge_mode);
+ return NULL;
+ }
+
+ /* Allocate the data object. */
+ ShrinkwrapBoundaryData *data = MEM_callocN(sizeof(ShrinkwrapBoundaryData), "ShrinkwrapBoundaryData");
+
+ data->edge_is_boundary = edge_is_boundary;
+
+ /* Build the boundary looptri bitmask. */
+ const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
+ int totlooptri = BKE_mesh_runtime_looptri_len(mesh);
+
+ BLI_bitmap *looptri_has_boundary = BLI_BITMAP_NEW(totlooptri, "ShrinkwrapBoundaryData::looptri_is_boundary");
+
+ for (int i = 0; i < totlooptri; i++) {
+ int edges[3];
+ BKE_mesh_looptri_get_real_edges(mesh, &mlooptri[i], edges);
+
+ for (int j = 0; j < 3; j++) {
+ if (edges[j] >= 0 && edge_mode[edges[j]]) {
+ BLI_BITMAP_ENABLE(looptri_has_boundary, i);
+ break;
+ }
+ }
+ }
+
+ data->looptri_has_boundary = looptri_has_boundary;
+
+ /* Find boundary vertices and build a mapping table for compact storage of data. */
+ int *vert_boundary_id = MEM_calloc_arrayN((size_t)mesh->totvert, sizeof(int), "ShrinkwrapBoundaryData::vert_boundary_id");
+
+ for (int i = 0; i < mesh->totedge; i++) {
+ if (edge_mode[i]) {
+ const MEdge *edge = &medge[i];
+
+ vert_boundary_id[edge->v1] = 1;
+ vert_boundary_id[edge->v2] = 1;
+ }
+ }
+
+ unsigned int num_boundary_verts = 0;
+
+ for (int i = 0; i < mesh->totvert; i++) {
+ vert_boundary_id[i] = (vert_boundary_id[i] != 0) ? (int)num_boundary_verts++ : -1;
+ }
+
+ data->vert_boundary_id = vert_boundary_id;
+ data->num_boundary_verts = num_boundary_verts;
+
+ /* Compute average directions. */
+ ShrinkwrapBoundaryVertData *boundary_verts = MEM_calloc_arrayN(num_boundary_verts, sizeof(*boundary_verts), "ShrinkwrapBoundaryData::boundary_verts");
+
+ signed char *vert_status = MEM_calloc_arrayN(num_boundary_verts, sizeof(char), __func__);
+
+ for (int i = 0; i < mesh->totedge; i++) {
+ if (edge_mode[i]) {
+ const MEdge *edge = &medge[i];
+
+ float dir[3];
+ sub_v3_v3v3(dir, mvert[edge->v2].co, mvert[edge->v1].co);
+ normalize_v3(dir);
+
+ merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v1], dir, 1);
+ merge_vert_dir(boundary_verts, vert_status, vert_boundary_id[edge->v2], dir, 2);
+ }
+ }
+
+ MEM_freeN(vert_status);
+
+ /* Finalize average direction and compute normal. */
+ for (int i = 0; i < mesh->totvert; i++) {
+ int bidx = vert_boundary_id[i];
+
+ if (bidx >= 0) {
+ ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx];
+ float no[3], tmp[3];
+
+ normalize_v3(vdata->direction);
+
+ normal_short_to_float_v3(no, mesh->mvert[i].no);
+ cross_v3_v3v3(tmp, no, vdata->direction);
+ cross_v3_v3v3(vdata->normal_plane, tmp, no);
+ normalize_v3(vdata->normal_plane);
+ }
+ }
+
+ data->boundary_verts = boundary_verts;
+
+ MEM_freeN(edge_mode);
+ return data;
+}
+
+void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh)
+{
+ BKE_shrinkwrap_discard_boundary_data(mesh);
+
+ mesh->runtime.shrinkwrap_data = shrinkwrap_build_boundary_data(mesh);
+}
+
/*
* Shrinkwrap to the nearest vertex
*
@@ -95,7 +344,7 @@ static void shrinkwrap_calc_nearest_vertex_cb_ex(
ShrinkwrapCalcCBData *data = userdata;
ShrinkwrapCalcData *calc = data->calc;
- BVHTreeFromMesh *treeData = data->treeData;
+ BVHTreeFromMesh *treeData = &data->tree->treeData;
BVHTreeNearest *nearest = tls->userdata_chunk;
float *co = calc->vertexCos[i];
@@ -151,24 +400,13 @@ static void shrinkwrap_calc_nearest_vertex_cb_ex(
static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
{
- BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
BVHTreeNearest nearest = NULL_BVHTreeNearest;
- if (calc->target != NULL && calc->target->getNumVerts(calc->target) == 0) {
- return;
- }
-
- TIMEIT_BENCH(bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_VERTS, 2), bvhtree_verts);
- if (treeData.tree == NULL) {
- OUT_OF_MEMORY();
- return;
- }
-
/* Setup nearest */
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
- ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ ShrinkwrapCalcCBData data = {.calc = calc, .tree = calc->tree};
ParallelRangeSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
@@ -177,8 +415,6 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
BLI_task_parallel_range(0, calc->numVerts,
&data, shrinkwrap_calc_nearest_vertex_cb_ex,
&settings);
-
- free_bvhtree_from_mesh(&treeData);
}
@@ -193,8 +429,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
bool BKE_shrinkwrap_project_normal(
char options, const float vert[3], const float dir[3],
const float ray_radius, const SpaceTransform *transf,
- BVHTree *tree, BVHTreeRayHit *hit,
- BVHTree_RayCastCallback callback, void *userdata)
+ ShrinkwrapTreeData *tree, BVHTreeRayHit *hit)
{
/* don't use this because this dist value could be incompatible
* this value used by the callback for comparing prev/new dist values.
@@ -229,7 +464,7 @@ bool BKE_shrinkwrap_project_normal(
hit_tmp.index = -1;
- BLI_bvhtree_ray_cast(tree, co, no, ray_radius, &hit_tmp, callback, userdata);
+ BLI_bvhtree_ray_cast(tree->bvh, co, no, ray_radius, &hit_tmp, tree->treeData.raycast_callback, &tree->treeData);
if (hit_tmp.index != -1) {
/* invert the normal first so face culling works on rotated objects */
@@ -237,7 +472,7 @@ bool BKE_shrinkwrap_project_normal(
BLI_space_transform_invert_normal(transf, hit_tmp.no);
}
- if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) {
+ if (options & MOD_SHRINKWRAP_CULL_TARGET_MASK) {
/* apply backface */
const float dot = dot_v3v3(dir, hit_tmp.no);
if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
@@ -271,12 +506,8 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
ShrinkwrapCalcCBData *data = userdata;
ShrinkwrapCalcData *calc = data->calc;
- void *treeData = data->treeData;
- void *auxData = data->auxData;
- BVHTree *targ_tree = data->targ_tree;
- BVHTree *aux_tree = data->aux_tree;
- void *targ_callback = data->targ_callback;
- void *aux_callback = data->aux_callback;
+ ShrinkwrapTreeData *tree = data->tree;
+ ShrinkwrapTreeData *aux_tree = data->aux_tree;
float *proj_axis = data->proj_axis;
SpaceTransform *local2aux = data->local2aux;
@@ -297,7 +528,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
}
if (calc->vert) {
- /* calc->vert contains verts from derivedMesh */
+ /* calc->vert contains verts from evaluated mesh. */
/* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
/* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
@@ -318,19 +549,25 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
hit->index = -1;
hit->dist = BVH_RAYCAST_DIST_MAX; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
+ bool is_aux = false;
+
/* Project over positive direction of axis */
if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, tmp_no, 0.0,
- local2aux, aux_tree, hit,
- aux_callback, auxData);
+ if (BKE_shrinkwrap_project_normal(
+ 0, tmp_co, tmp_no, 0.0,
+ local2aux, aux_tree, hit))
+ {
+ is_aux = true;
+ }
}
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0,
- &calc->local2target, targ_tree, hit,
- targ_callback, treeData);
+ if (BKE_shrinkwrap_project_normal(
+ calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0,
+ &calc->local2target, tree, hit))
+ {
+ is_aux = false;
+ }
}
/* Project over negative direction of axis */
@@ -338,34 +575,54 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
float inv_no[3];
negate_v3_v3(inv_no, tmp_no);
+ char options = calc->smd->shrinkOpts;
+
+ if ((options & MOD_SHRINKWRAP_INVERT_CULL_TARGET) && (options & MOD_SHRINKWRAP_CULL_TARGET_MASK)) {
+ options ^= MOD_SHRINKWRAP_CULL_TARGET_MASK;
+ }
+
if (aux_tree) {
- BKE_shrinkwrap_project_normal(
- 0, tmp_co, inv_no, 0.0,
- local2aux, aux_tree, hit,
- aux_callback, auxData);
+ if (BKE_shrinkwrap_project_normal(
+ 0, tmp_co, inv_no, 0.0,
+ local2aux, aux_tree, hit))
+ {
+ is_aux = true;
+ }
}
- BKE_shrinkwrap_project_normal(
- calc->smd->shrinkOpts, tmp_co, inv_no, 0.0,
- &calc->local2target, targ_tree, hit,
- targ_callback, treeData);
+ if (BKE_shrinkwrap_project_normal(
+ options, tmp_co, inv_no, 0.0,
+ &calc->local2target, tree, hit))
+ {
+ is_aux = false;
+ }
}
/* don't set the initial dist (which is more efficient),
* because its calculated in the targets space, we want the dist in our own space */
if (proj_limit_squared != 0.0f) {
- if (len_squared_v3v3(hit->co, co) > proj_limit_squared) {
+ if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) {
hit->index = -1;
}
}
if (hit->index != -1) {
- madd_v3_v3v3fl(hit->co, hit->co, tmp_no, calc->keepDist);
+ if (is_aux) {
+ BKE_shrinkwrap_snap_point_to_surface(
+ aux_tree, local2aux, calc->smd->shrinkMode,
+ hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co);
+ }
+ else {
+ BKE_shrinkwrap_snap_point_to_surface(
+ tree, &calc->local2target, calc->smd->shrinkMode,
+ hit->index, hit->co, hit->no, calc->keepDist, tmp_co, hit->co);
+ }
+
interp_v3_v3v3(co, co, hit->co, weight);
}
}
-static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render)
+static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
{
/* Options about projection direction */
float proj_axis[3] = {0.0f, 0.0f, 0.0f};
@@ -376,11 +633,12 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
* for finding the best hit, to get the real dist,
* measure the len_v3v3() from the input coord to hit.co */
BVHTreeRayHit hit;
- void *treeData = NULL;
/* auxiliary target */
- DerivedMesh *auxMesh = NULL;
- void *auxData = NULL;
+ Mesh *auxMesh = NULL;
+ bool auxMesh_free;
+ ShrinkwrapTreeData *aux_tree = NULL;
+ ShrinkwrapTreeData aux_tree_stack;
SpaceTransform local2aux;
/* If the user doesn't allows to project in any direction of projection axis
@@ -388,10 +646,6 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
return;
- if (calc->target != NULL && calc->target->getNumPolys(calc->target) == 0) {
- return;
- }
-
/* Prepare data to retrieve the direction in which we should project each vertex */
if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
if (calc->vert == NULL) return;
@@ -412,97 +666,382 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
}
if (calc->smd->auxTarget) {
- auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render);
+ auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->smd->auxTarget, &auxMesh_free);
if (!auxMesh)
return;
BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget);
}
- /* use editmesh to avoid array allocation */
- BMEditMesh *emtarget = NULL, *emaux = NULL;
- union {
- BVHTreeFromEditMesh emtreedata;
- BVHTreeFromMesh dmtreedata;
- } treedata_stack, auxdata_stack;
+ if (BKE_shrinkwrap_init_tree(&aux_tree_stack, auxMesh, calc->smd->shrinkType, calc->smd->shrinkMode, false)) {
+ aux_tree = &aux_tree_stack;
+ }
- BVHTree *targ_tree;
- void *targ_callback;
- if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) {
- emtarget = BKE_editmesh_from_object(calc->smd->target);
- if ((targ_tree = bvhtree_from_editmesh_looptri(
- &treedata_stack.emtreedata, emtarget, 0.0, 4, 6, &calc->target->bvhCache)))
- {
- targ_callback = treedata_stack.emtreedata.raycast_callback;
- treeData = &treedata_stack.emtreedata;
- }
+ /* After successfully build the trees, start projection vertices. */
+ ShrinkwrapCalcCBData data = {
+ .calc = calc, .tree = calc->tree, .aux_tree = aux_tree,
+ .proj_axis = proj_axis, .local2aux = &local2aux
+ };
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
+ settings.userdata_chunk = &hit;
+ settings.userdata_chunk_size = sizeof(hit);
+ BLI_task_parallel_range(0, calc->numVerts,
+ &data,
+ shrinkwrap_calc_normal_projection_cb_ex,
+ &settings);
+
+ /* free data structures */
+ if (aux_tree) {
+ BKE_shrinkwrap_free_tree(aux_tree);
}
- else {
- if ((targ_tree = bvhtree_from_mesh_get(
- &treedata_stack.dmtreedata, calc->target, BVHTREE_FROM_LOOPTRI, 4)))
- {
- targ_callback = treedata_stack.dmtreedata.raycast_callback;
- treeData = &treedata_stack.dmtreedata;
- }
- }
- if (targ_tree) {
- BVHTree *aux_tree = NULL;
- void *aux_callback = NULL;
- if (auxMesh != NULL && auxMesh->getNumPolys(auxMesh) != 0) {
- /* use editmesh to avoid array allocation */
- if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) {
- emaux = BKE_editmesh_from_object(calc->smd->auxTarget);
- if ((aux_tree = bvhtree_from_editmesh_looptri(
- &auxdata_stack.emtreedata, emaux, 0.0, 4, 6, &auxMesh->bvhCache)))
- {
- aux_callback = auxdata_stack.emtreedata.raycast_callback;
- auxData = &auxdata_stack.emtreedata;
+ if (auxMesh != NULL && auxMesh_free) {
+ BKE_id_free(NULL, auxMesh);
+ }
+}
+
+/*
+ * Shrinkwrap Target Surface Project mode
+ *
+ * It uses Newton's method to find a surface location with its
+ * smooth normal pointing at the original point.
+ *
+ * The equation system on barycentric weights and normal multiplier:
+ *
+ * (w0*V0 + w1*V1 + w2*V2) + l * (w0*N0 + w1*N1 + w2*N2) - CO = 0
+ * w0 + w1 + w2 = 1
+ *
+ * The actual solution vector is [ w0, w1, l ], with w2 eliminated.
+ */
+
+//#define TRACE_TARGET_PROJECT
+
+typedef struct TargetProjectTriData {
+ const float **vtri_co;
+ const float (*vtri_no)[3];
+ const float *point_co;
+
+ float n0_minus_n2[3], n1_minus_n2[3];
+ float c0_minus_c2[3], c1_minus_c2[3];
+
+ /* Current interpolated position and normal. */
+ float co_interp[3], no_interp[3];
+} TargetProjectTriData;
+
+/* Computes the deviation of the equation system from goal. */
+static void target_project_tri_deviation(void *userdata, const float x[3], float r_delta[3])
+{
+ TargetProjectTriData *data = userdata;
+
+ float w[3] = { x[0], x[1], 1.0f - x[0] - x[1] };
+ interp_v3_v3v3v3(data->co_interp, data->vtri_co[0], data->vtri_co[1], data->vtri_co[2], w);
+ interp_v3_v3v3v3(data->no_interp, data->vtri_no[0], data->vtri_no[1], data->vtri_no[2], w);
+
+ madd_v3_v3v3fl(r_delta, data->co_interp, data->no_interp, x[2]);
+ sub_v3_v3(r_delta, data->point_co);
+}
+
+/* Computes the Jacobian matrix of the equation system. */
+static void target_project_tri_jacobian(void *userdata, const float x[3], float r_jacobian[3][3])
+{
+ TargetProjectTriData *data = userdata;
+
+ madd_v3_v3v3fl(r_jacobian[0], data->c0_minus_c2, data->n0_minus_n2, x[2]);
+ madd_v3_v3v3fl(r_jacobian[1], data->c1_minus_c2, data->n1_minus_n2, x[2]);
+
+ copy_v3_v3(r_jacobian[2], data->vtri_no[2]);
+ madd_v3_v3fl(r_jacobian[2], data->n0_minus_n2, x[0]);
+ madd_v3_v3fl(r_jacobian[2], data->n1_minus_n2, x[1]);
+}
+
+/* Clamp barycentric weights to the triangle. */
+static void target_project_tri_clamp(float x[3])
+{
+ if (x[0] < 0.0f) {
+ x[0] = 0.0f;
+ }
+ if (x[1] < 0.0f) {
+ x[1] = 0.0f;
+ }
+ if (x[0] + x[1] > 1.0f) {
+ x[0] = x[0] / (x[0] + x[1]);
+ x[1] = 1.0f - x[0];
+ }
+}
+
+/* Correct the Newton's method step to keep the coordinates within the triangle. */
+static bool target_project_tri_correct(void *UNUSED(userdata), const float x[3], float step[3], float x_next[3])
+{
+ /* Insignificant correction threshold */
+ const float epsilon = 1e-6f;
+ const float dir_epsilon = 0.05f;
+ bool fixed = false, locked = false;
+
+ /* Weight 0 and 1 boundary check. */
+ for (int i = 0; i < 2; i++) {
+ if (step[i] > x[i]) {
+ if (step[i] > dir_epsilon * fabsf(step[1 - i])) {
+ /* Abort if the solution is clearly outside the domain. */
+ if (x[i] < epsilon) {
+ return false;
}
+
+ /* Scale a significant step down to arrive at the boundary. */
+ mul_v3_fl(step, x[i] / step[i]);
+ fixed = true;
}
else {
- if ((aux_tree = bvhtree_from_mesh_get(
- &auxdata_stack.dmtreedata, auxMesh, BVHTREE_FROM_LOOPTRI, 4)) != NULL)
- {
- aux_callback = auxdata_stack.dmtreedata.raycast_callback;
- auxData = &auxdata_stack.dmtreedata;
- }
+ /* Reset precision errors to stay at the boundary. */
+ step[i] = x[i];
+ fixed = locked = true;
}
}
- /* After sucessufuly build the trees, start projection vertexs */
- ShrinkwrapCalcCBData data = {
- .calc = calc,
- .treeData = treeData, .targ_tree = targ_tree, .targ_callback = targ_callback,
- .auxData = auxData, .aux_tree = aux_tree, .aux_callback = aux_callback,
- .proj_axis = proj_axis, .local2aux = &local2aux,
- };
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
- settings.userdata_chunk = &hit;
- settings.userdata_chunk_size = sizeof(hit);
- BLI_task_parallel_range(0, calc->numVerts,
- &data,
- shrinkwrap_calc_normal_projection_cb_ex,
- &settings);
}
- /* free data structures */
- if (treeData) {
- if (emtarget) {
- free_bvhtree_from_editmesh(treeData);
+ /* Weight 2 boundary check. */
+ float sum = x[0] + x[1];
+ float sstep = step[0] + step[1];
+
+ if (sum - sstep > 1.0f) {
+ if (sstep < -dir_epsilon * (fabsf(step[0]) + fabsf(step[1]))) {
+ /* Abort if the solution is clearly outside the domain. */
+ if (sum > 1.0f - epsilon) {
+ return false;
+ }
+
+ /* Scale a significant step down to arrive at the boundary. */
+ mul_v3_fl(step, (1.0f - sum) / -sstep);
+ fixed = true;
}
else {
- free_bvhtree_from_mesh(treeData);
+ /* Reset precision errors to stay at the boundary. */
+ if (locked) {
+ step[0] = step[1] = 0.0f;
+ }
+ else {
+ step[0] -= 0.5f * sstep;
+ step[1] = -step[0];
+ fixed = true;
+ }
}
}
- if (auxData) {
- if (emaux) {
- free_bvhtree_from_editmesh(auxData);
+ /* Recompute and clamp the new coordinates after step correction. */
+ if (fixed) {
+ sub_v3_v3v3(x_next, x, step);
+ target_project_tri_clamp(x_next);
+ }
+
+ return true;
+}
+
+static bool target_project_solve_point_tri(
+ const float *vtri_co[3], const float vtri_no[3][3], const float point_co[3],
+ const float hit_co[3], float hit_dist_sq,
+ float r_hit_co[3], float r_hit_no[3])
+{
+ float x[3], tmp[3];
+ float dist = sqrtf(hit_dist_sq);
+ float epsilon = dist * 1.0e-5f;
+
+ CLAMP_MIN(epsilon, 1.0e-5f);
+
+ /* Initial solution vector: barycentric weights plus distance along normal. */
+ interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co);
+
+ interp_v3_v3v3v3(r_hit_no, UNPACK3(vtri_no), x);
+ sub_v3_v3v3(tmp, point_co, hit_co);
+
+ x[2] = (dot_v3v3(tmp, r_hit_no) < 0) ? -dist : dist;
+
+ /* Solve the equations iteratively. */
+ TargetProjectTriData tri_data = { .vtri_co = vtri_co, .vtri_no = vtri_no, .point_co = point_co };
+
+ sub_v3_v3v3(tri_data.n0_minus_n2, vtri_no[0], vtri_no[2]);
+ sub_v3_v3v3(tri_data.n1_minus_n2, vtri_no[1], vtri_no[2]);
+ sub_v3_v3v3(tri_data.c0_minus_c2, vtri_co[0], vtri_co[2]);
+ sub_v3_v3v3(tri_data.c1_minus_c2, vtri_co[1], vtri_co[2]);
+
+ target_project_tri_clamp(x);
+
+#ifdef TRACE_TARGET_PROJECT
+ const bool trace = true;
+#else
+ const bool trace = false;
+#endif
+
+ bool ok = BLI_newton3d_solve(target_project_tri_deviation, target_project_tri_jacobian, target_project_tri_correct, &tri_data, epsilon, 20, trace, x, x);
+
+ if (ok) {
+ copy_v3_v3(r_hit_co, tri_data.co_interp);
+ copy_v3_v3(r_hit_no, tri_data.no_interp);
+
+ return true;
+ }
+
+ return false;
+}
+
+static bool update_hit(BVHTreeNearest *nearest, int index, const float co[3], const float hit_co[3], const float hit_no[3])
+{
+ float dist_sq = len_squared_v3v3(hit_co, co);
+
+ if (dist_sq < nearest->dist_sq) {
+#ifdef TRACE_TARGET_PROJECT
+ printf("===> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq);
+#endif
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, hit_co);
+ normalize_v3_v3(nearest->no, hit_no);
+ return true;
+ }
+
+ return false;
+}
+
+/* Target projection on a non-manifold boundary edge - treats it like an infinitely thin cylinder. */
+static void target_project_edge(const ShrinkwrapTreeData *tree, int index, const float co[3], BVHTreeNearest *nearest, int eidx)
+{
+ const BVHTreeFromMesh *data = &tree->treeData;
+ const MEdge *edge = &tree->mesh->medge[eidx];
+ const float *vedge_co[2] = { data->vert[edge->v1].co, data->vert[edge->v2].co };
+
+#ifdef TRACE_TARGET_PROJECT
+ printf("EDGE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f)\n", eidx, UNPACK3(vedge_co[0]), UNPACK3(vedge_co[1]));
+#endif
+
+ /* Retrieve boundary vertex IDs */
+ const int *vert_boundary_id = tree->boundary->vert_boundary_id;
+ int bid1 = vert_boundary_id[edge->v1], bid2 = vert_boundary_id[edge->v2];
+
+ if (bid1 < 0 || bid2 < 0) {
+ return;
+ }
+
+ /* Retrieve boundary vertex normals and align them to direction. */
+ const ShrinkwrapBoundaryVertData *boundary_verts = tree->boundary->boundary_verts;
+ float vedge_dir[2][3], dir[3];
+
+ copy_v3_v3(vedge_dir[0], boundary_verts[bid1].normal_plane);
+ copy_v3_v3(vedge_dir[1], boundary_verts[bid2].normal_plane);
+
+ sub_v3_v3v3(dir, vedge_co[1], vedge_co[0]);
+
+ if (dot_v3v3(boundary_verts[bid1].direction, dir) < 0) {
+ negate_v3(vedge_dir[0]);
+ }
+ if (dot_v3v3(boundary_verts[bid2].direction, dir) < 0) {
+ negate_v3(vedge_dir[1]);
+ }
+
+ /* Solve a quadratic equation: lerp(d0,d1,x) * (co - lerp(v0,v1,x)) = 0 */
+ float d0v0 = dot_v3v3(vedge_dir[0], vedge_co[0]), d0v1 = dot_v3v3(vedge_dir[0], vedge_co[1]);
+ float d1v0 = dot_v3v3(vedge_dir[1], vedge_co[0]), d1v1 = dot_v3v3(vedge_dir[1], vedge_co[1]);
+ float d0co = dot_v3v3(vedge_dir[0], co);
+
+ float a = d0v1 - d0v0 + d1v0 - d1v1;
+ float b = 2 * d0v0 - d0v1 - d0co - d1v0 + dot_v3v3(vedge_dir[1], co);
+ float c = d0co - d0v0;
+ float det = b * b - 4 * a * c;
+
+ if (det >= 0) {
+ const float epsilon = 1e-6f;
+ float sdet = sqrtf(det);
+ float hit_co[3], hit_no[3];
+
+ for (int i = (det > 0 ? 2 : 0); i >= 0; i -= 2) {
+ float x = (- b + ((float)i - 1) * sdet) / (2 * a);
+
+ if (x >= -epsilon && x <= 1.0f + epsilon) {
+ CLAMP(x, 0, 1);
+
+ float vedge_no[2][3];
+ normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no);
+ normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no);
+
+ interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x);
+ interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x);
+
+ update_hit(nearest, index, co, hit_co, hit_no);
+ }
}
- else {
- free_bvhtree_from_mesh(auxData);
+ }
+}
+
+/* Target normal projection BVH callback - based on mesh_looptri_nearest_point. */
+static void mesh_looptri_target_project(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
+{
+ const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata;
+ const BVHTreeFromMesh *data = &tree->treeData;
+ const MLoopTri *lt = &data->looptri[index];
+ const MLoop *loop[3] = { &data->loop[lt->tri[0]], &data->loop[lt->tri[1]], &data->loop[lt->tri[2]] };
+ const MVert *vtri[3] = { &data->vert[loop[0]->v], &data->vert[loop[1]->v], &data->vert[loop[2]->v] };
+ const float *vtri_co[3] = { vtri[0]->co, vtri[1]->co, vtri[2]->co };
+ float raw_hit_co[3], hit_co[3], hit_no[3], dist_sq, vtri_no[3][3];
+
+ /* First find the closest point and bail out if it's worse than the current solution. */
+ closest_on_tri_to_point_v3(raw_hit_co, co, UNPACK3(vtri_co));
+ dist_sq = len_squared_v3v3(co, raw_hit_co);
+
+#ifdef TRACE_TARGET_PROJECT
+ printf("TRIANGLE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) %g %g\n",
+ index, UNPACK3(vtri_co[0]), UNPACK3(vtri_co[1]), UNPACK3(vtri_co[2]), dist_sq, nearest->dist_sq);
+#endif
+
+ if (dist_sq >= nearest->dist_sq)
+ return;
+
+ /* Decode normals */
+ normal_short_to_float_v3(vtri_no[0], vtri[0]->no);
+ normal_short_to_float_v3(vtri_no[1], vtri[1]->no);
+ normal_short_to_float_v3(vtri_no[2], vtri[2]->no);
+
+ /* Solve the equations for the triangle */
+ if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) {
+ update_hit(nearest, index, co, hit_co, hit_no);
+ }
+ /* Boundary edges */
+ else if (tree->boundary && BLI_BITMAP_TEST(tree->boundary->looptri_has_boundary, index)) {
+ const BLI_bitmap *is_boundary = tree->boundary->edge_is_boundary;
+ int edges[3];
+
+ BKE_mesh_looptri_get_real_edges(tree->mesh, lt, edges);
+
+ for (int i = 0; i < 3; i++) {
+ if (edges[i] >= 0 && BLI_BITMAP_TEST(is_boundary, edges[i])) {
+ target_project_edge(tree, index, co, nearest, edges[i]);
+ }
+ }
+ }
+}
+
+/*
+ * Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
+ */
+void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree, BVHTreeNearest *nearest, float co[3], int type)
+{
+ BVHTreeFromMesh *treeData = &tree->treeData;
+
+ if (type == MOD_SHRINKWRAP_TARGET_PROJECT) {
+#ifdef TRACE_TARGET_PROJECT
+ printf("====== TARGET PROJECT START ======\n");
+#endif
+
+ BLI_bvhtree_find_nearest_ex(tree->bvh, co, nearest, mesh_looptri_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER);
+
+#ifdef TRACE_TARGET_PROJECT
+ printf("====== TARGET PROJECT END: %d %g ======\n", nearest->index, nearest->dist_sq);
+#endif
+
+ if (nearest->index < 0) {
+ /* fallback to simple nearest */
+ BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
}
}
+ else {
+ BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
+ }
}
/*
@@ -519,7 +1058,6 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(
ShrinkwrapCalcCBData *data = userdata;
ShrinkwrapCalcData *calc = data->calc;
- BVHTreeFromMesh *treeData = data->treeData;
BVHTreeNearest *nearest = tls->userdata_chunk;
float *co = calc->vertexCos[i];
@@ -548,31 +1086,26 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(
* If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
* so we can initiate the "nearest.dist" with the expected value to that last hit.
* This will lead in pruning of the search tree. */
- if (nearest->index != -1)
- nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ if (nearest->index != -1) {
+ if (calc->smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
+ /* Heuristic doesn't work because of additional restrictions. */
+ nearest->index = -1;
+ nearest->dist_sq = FLT_MAX;
+ }
+ else {
+ nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
+ }
+ }
else
nearest->dist_sq = FLT_MAX;
- BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
+ BKE_shrinkwrap_find_nearest_surface(data->tree, nearest, tmp_co, calc->smd->shrinkType);
/* Found the nearest vertex */
if (nearest->index != -1) {
- if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
- /* Make the vertex stay on the front side of the face */
- madd_v3_v3v3fl(tmp_co, nearest->co, nearest->no, calc->keepDist);
- }
- else {
- /* Adjusting the vertex weight,
- * so that after interpolating it keeps a certain distance from the nearest position */
- const float dist = sasqrt(nearest->dist_sq);
- if (dist > FLT_EPSILON) {
- /* linear interpolation */
- interp_v3_v3v3(tmp_co, tmp_co, nearest->co, (dist - calc->keepDist) / dist);
- }
- else {
- copy_v3_v3(tmp_co, nearest->co);
- }
- }
+ BKE_shrinkwrap_snap_point_to_surface(
+ data->tree, NULL, calc->smd->shrinkMode,
+ nearest->index, nearest->co, nearest->no, calc->keepDist, tmp_co, tmp_co);
/* Convert the coordinates back to mesh coordinates */
BLI_space_transform_invert(&calc->local2target, tmp_co);
@@ -580,28 +1113,161 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex(
}
}
-static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+/**
+ * Compute a smooth normal of the target (if applicable) at the hit location.
+ *
+ * \param tree: information about the mesh
+ * \param transform: transform from the hit coordinate space to the object space; may be null
+ * \param r_no: output in hit coordinate space; may be shared with inputs
+ */
+void BKE_shrinkwrap_compute_smooth_normal(
+ const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
+ int looptri_idx, const float hit_co[3], const float hit_no[3], float r_no[3])
{
- BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
- BVHTreeNearest nearest = NULL_BVHTreeNearest;
+ const BVHTreeFromMesh *treeData = &tree->treeData;
+ const MLoopTri *tri = &treeData->looptri[looptri_idx];
+
+ /* Interpolate smooth normals if enabled. */
+ if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) {
+ const MVert *verts[] = {
+ &treeData->vert[treeData->loop[tri->tri[0]].v],
+ &treeData->vert[treeData->loop[tri->tri[1]].v],
+ &treeData->vert[treeData->loop[tri->tri[2]].v],
+ };
+ float w[3], no[3][3], tmp_co[3];
- if (calc->target->getNumPolys(calc->target) == 0) {
- return;
+ /* Custom and auto smooth split normals. */
+ if (tree->clnors) {
+ copy_v3_v3(no[0], tree->clnors[tri->tri[0]]);
+ copy_v3_v3(no[1], tree->clnors[tri->tri[1]]);
+ copy_v3_v3(no[2], tree->clnors[tri->tri[2]]);
+ }
+ /* Ordinary vertex normals. */
+ else {
+ normal_short_to_float_v3(no[0], verts[0]->no);
+ normal_short_to_float_v3(no[1], verts[1]->no);
+ normal_short_to_float_v3(no[2], verts[2]->no);
+ }
+
+ /* Barycentric weights from hit point. */
+ copy_v3_v3(tmp_co, hit_co);
+
+ if (transform) {
+ BLI_space_transform_apply(transform, tmp_co);
+ }
+
+ interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co);
+
+ /* Interpolate using weights. */
+ interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w);
+
+ if (transform) {
+ BLI_space_transform_invert_normal(transform, r_no);
+ }
+ else {
+ normalize_v3(r_no);
+ }
}
+ /* Use the looptri normal if flat. */
+ else {
+ copy_v3_v3(r_no, hit_no);
+ }
+}
- /* Create a bvh-tree of the given target */
- bvhtree_from_mesh_get(&treeData, calc->target, BVHTREE_FROM_LOOPTRI, 2);
- if (treeData.tree == NULL) {
- OUT_OF_MEMORY();
- return;
+/* Helper for MOD_SHRINKWRAP_INSIDE, MOD_SHRINKWRAP_OUTSIDE and MOD_SHRINKWRAP_OUTSIDE_SURFACE. */
+static void shrinkwrap_snap_with_side(float r_point_co[3], const float point_co[3], const float hit_co[3], const float hit_no[3], float goal_dist, float forcesign, bool forcesnap)
+{
+ float dist = len_v3v3(point_co, hit_co);
+
+ /* If exactly on the surface, push out along normal */
+ if (dist < FLT_EPSILON) {
+ madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign);
}
+ /* Move to the correct side if needed */
+ else {
+ float delta[3];
+ sub_v3_v3v3(delta, point_co, hit_co);
+ float dsign = signf(dot_v3v3(delta, hit_no));
+
+ /* If on the wrong side or too close, move to correct */
+ if (forcesnap || dsign * forcesign < 0 || dist < goal_dist) {
+ interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign * forcesign) / dist);
+ }
+ else {
+ copy_v3_v3(r_point_co, point_co);
+ }
+ }
+}
+
+/**
+ * Apply the shrink to surface modes to the given original coordinates and nearest point.
+ *
+ * \param tree: mesh data for smooth normals
+ * \param transform: transform from the hit coordinate space to the object space; may be null
+ * \param r_point_co: may be the same memory location as point_co, hit_co, or hit_no.
+ */
+void BKE_shrinkwrap_snap_point_to_surface(
+ const struct ShrinkwrapTreeData *tree, const struct SpaceTransform *transform,
+ int mode, int hit_idx, const float hit_co[3], const float hit_no[3], float goal_dist,
+ const float point_co[3], float r_point_co[3])
+{
+ float dist, tmp[3];
+
+ switch (mode) {
+ /* Offsets along the line between point_co and hit_co. */
+ case MOD_SHRINKWRAP_ON_SURFACE:
+ if (goal_dist > 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) {
+ interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ break;
+
+ case MOD_SHRINKWRAP_INSIDE:
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false);
+ break;
+
+ case MOD_SHRINKWRAP_OUTSIDE:
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false);
+ break;
+
+ case MOD_SHRINKWRAP_OUTSIDE_SURFACE:
+ if (goal_dist > 0) {
+ shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ break;
+
+ /* Offsets along the normal */
+ case MOD_SHRINKWRAP_ABOVE_SURFACE:
+ if (goal_dist > 0) {
+ BKE_shrinkwrap_compute_smooth_normal(tree, transform, hit_idx, hit_co, hit_no, tmp);
+ madd_v3_v3v3fl(r_point_co, hit_co, tmp, goal_dist);
+ }
+ else {
+ copy_v3_v3(r_point_co, hit_co);
+ }
+ break;
+
+ default:
+ printf("Unknown Shrinkwrap surface snap mode: %d\n", mode);
+ copy_v3_v3(r_point_co, hit_co);
+ }
+}
+
+static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
+{
+ BVHTreeNearest nearest = NULL_BVHTreeNearest;
/* Setup nearest */
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
/* Find the nearest vertex */
- ShrinkwrapCalcCBData data = {.calc = calc, .treeData = &treeData};
+ ShrinkwrapCalcCBData data = {.calc = calc, .tree = calc->tree};
ParallelRangeSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT);
@@ -611,17 +1277,16 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
&data,
shrinkwrap_calc_nearest_surface_point_cb_ex,
&settings);
-
- free_bvhtree_from_mesh(&treeData);
}
/* Main shrinkwrap function */
-void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm,
- float (*vertexCos)[3], int numVerts, bool for_render)
+void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, struct Scene *scene, Object *ob, Mesh *mesh,
+ float (*vertexCos)[3], int numVerts)
{
DerivedMesh *ss_mesh = NULL;
ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
+ bool target_free = false;
/* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */
if (smd->target == ob) smd->target = NULL;
@@ -637,8 +1302,8 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
/* DeformVertex */
calc.vgroup = defgroup_name_index(calc.ob, calc.smd->vgroup_name);
- if (dm) {
- calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ if (mesh) {
+ calc.dvert = mesh->dvert;
}
else if (calc.ob->type == OB_LATTICE) {
calc.dvert = BKE_lattice_deform_verts_get(calc.ob);
@@ -646,7 +1311,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
if (smd->target) {
- calc.target = object_get_derived_final(smd->target, for_render);
+ calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(smd->target, &target_free);
/* TODO there might be several "bugs" on non-uniform scales matrixs
* because it will no longer be nearest surface, not sphere projection
@@ -661,10 +1326,10 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
calc.vgroup = defgroup_name_index(calc.ob, smd->vgroup_name);
- if (dm != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
+ if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
/* Setup arrays to get vertexs positions, normals and deform weights */
- calc.vert = dm->getVertDataArray(dm, CD_MVERT);
- calc.dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ calc.vert = mesh->mvert;
+ calc.dvert = mesh->dvert;
/* Using vertexs positions/normals as if a subsurface was applied */
if (smd->subsurfLevels) {
@@ -672,7 +1337,10 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */
ssmd.levels = smd->subsurfLevels; /* levels */
- ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0);
+ /* TODO to be moved to Mesh once we are done with changes in subsurf code. */
+ DerivedMesh *dm = CDDM_from_mesh(mesh);
+
+ ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, scene, NULL, (ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : 0);
if (ss_mesh) {
calc.vert = ss_mesh->getVertDataArray(ss_mesh, CD_MVERT);
@@ -684,29 +1352,42 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
}
/* Just to make sure we are not leaving any memory behind */
- assert(ssmd.emCache == NULL);
- assert(ssmd.mCache == NULL);
+ BLI_assert(ssmd.emCache == NULL);
+ BLI_assert(ssmd.mCache == NULL);
+
+ dm->release(dm);
}
}
/* Projecting target defined - lets work! */
- if (calc.target) {
+ ShrinkwrapTreeData tree;
+
+ if (BKE_shrinkwrap_init_tree(&tree, calc.target, smd->shrinkType, smd->shrinkMode, false)) {
+ calc.tree = &tree;
+
switch (smd->shrinkType) {
case MOD_SHRINKWRAP_NEAREST_SURFACE:
+ case MOD_SHRINKWRAP_TARGET_PROJECT:
TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface);
break;
case MOD_SHRINKWRAP_PROJECT:
- TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc, for_render), deform_project);
+ TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project);
break;
case MOD_SHRINKWRAP_NEAREST_VERTEX:
TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex);
break;
}
+
+ BKE_shrinkwrap_free_tree(&tree);
}
/* free memory */
if (ss_mesh)
ss_mesh->release(ss_mesh);
+
+ if (target_free && calc.target) {
+ BKE_id_free(NULL, calc.target);
+ }
}
diff --git a/source/blender/blenkernel/intern/sketch.c b/source/blender/blenkernel/intern/sketch.c
deleted file mode 100644
index 0bf7a9f278e..00000000000
--- a/source/blender/blenkernel/intern/sketch.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/sketch.c
- * \ingroup bke
- */
-
-
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_sketch.h"
-
-
-#include "DNA_userdef_types.h"
-
-void freeSketch(SK_Sketch *sketch)
-{
- SK_Stroke *stk, *next;
-
- for (stk = sketch->strokes.first; stk; stk = next) {
- next = stk->next;
-
- sk_freeStroke(stk);
- }
-
- MEM_freeN(sketch);
-}
-
-SK_Sketch *createSketch(void)
-{
- SK_Sketch *sketch;
-
- sketch = MEM_callocN(sizeof(SK_Sketch), "SK_Sketch");
-
- sketch->active_stroke = NULL;
- sketch->gesture = NULL;
-
- BLI_listbase_clear(&sketch->strokes);
-
- return sketch;
-}
-
-void sk_initPoint(SK_Point *pt, SK_DrawData *dd, const float no[3])
-{
- if (no) {
- normalize_v3_v3(pt->no, no);
- }
- else {
- pt->no[0] = 0.0f;
- pt->no[1] = 0.0f;
- pt->no[2] = 1.0f;
- }
- pt->p2d[0] = dd->mval[0];
- pt->p2d[1] = dd->mval[1];
-
- pt->size = 0.0f;
- pt->type = PT_CONTINUOUS;
- pt->mode = PT_SNAP;
- /* more init code here */
-}
-
-void sk_copyPoint(SK_Point *dst, SK_Point *src)
-{
- memcpy(dst, src, sizeof(SK_Point));
-}
-
-void sk_allocStrokeBuffer(SK_Stroke *stk)
-{
- stk->points = MEM_callocN(sizeof(SK_Point) * stk->buf_size, "SK_Point buffer");
-}
-
-void sk_freeStroke(SK_Stroke *stk)
-{
- MEM_freeN(stk->points);
- MEM_freeN(stk);
-}
-
-SK_Stroke *sk_createStroke(void)
-{
- SK_Stroke *stk;
-
- stk = MEM_callocN(sizeof(SK_Stroke), "SK_Stroke");
-
- stk->selected = 0;
- stk->nb_points = 0;
- stk->buf_size = SK_Stroke_BUFFER_INIT_SIZE;
-
- sk_allocStrokeBuffer(stk);
-
- return stk;
-}
-
-void sk_shrinkStrokeBuffer(SK_Stroke *stk)
-{
- if (stk->nb_points < stk->buf_size) {
- SK_Point *old_points = stk->points;
-
- stk->buf_size = stk->nb_points;
-
- sk_allocStrokeBuffer(stk);
-
- memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
-
- MEM_freeN(old_points);
- }
-}
-
-void sk_growStrokeBuffer(SK_Stroke *stk)
-{
- if (stk->nb_points == stk->buf_size) {
- SK_Point *old_points = stk->points;
-
- stk->buf_size *= 2;
-
- sk_allocStrokeBuffer(stk);
-
- memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
-
- MEM_freeN(old_points);
- }
-}
-
-void sk_growStrokeBufferN(SK_Stroke *stk, int n)
-{
- if (stk->nb_points + n > stk->buf_size) {
- SK_Point *old_points = stk->points;
-
- while (stk->nb_points + n > stk->buf_size) {
- stk->buf_size *= 2;
- }
-
- sk_allocStrokeBuffer(stk);
-
- memcpy(stk->points, old_points, sizeof(SK_Point) * stk->nb_points);
-
- MEM_freeN(old_points);
- }
-}
-
-
-void sk_replaceStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
-{
- memcpy(stk->points + n, pt, sizeof(SK_Point));
-}
-
-void sk_insertStrokePoint(SK_Stroke *stk, SK_Point *pt, int n)
-{
- int size = stk->nb_points - n;
-
- sk_growStrokeBuffer(stk);
-
- memmove(stk->points + n + 1, stk->points + n, size * sizeof(SK_Point));
-
- memcpy(stk->points + n, pt, sizeof(SK_Point));
-
- stk->nb_points++;
-}
-
-void sk_appendStrokePoint(SK_Stroke *stk, SK_Point *pt)
-{
- sk_growStrokeBuffer(stk);
-
- memcpy(stk->points + stk->nb_points, pt, sizeof(SK_Point));
-
- stk->nb_points++;
-}
-
-void sk_insertStrokePoints(SK_Stroke *stk, SK_Point *pts, int len, int start, int end)
-{
- int size = end - start;
-
- sk_growStrokeBufferN(stk, len - size);
-
- if (len != size) {
- int tail_size = stk->nb_points - end;
-
- memmove(stk->points + start + len, stk->points + end, tail_size * sizeof(SK_Point));
- }
-
- memcpy(stk->points + start, pts, len * sizeof(SK_Point));
-
- stk->nb_points += len - size;
-}
-
-void sk_trimStroke(SK_Stroke *stk, int start, int end)
-{
- int size = end - start + 1;
-
- if (start > 0) {
- memmove(stk->points, stk->points + start, size * sizeof(SK_Point));
- }
-
- stk->nb_points = size;
-}
-
-void sk_straightenStroke(SK_Stroke *stk, int start, int end, float p_start[3], float p_end[3])
-{
- SK_Point pt1, pt2;
- SK_Point *prev, *next;
- float delta_p[3];
- int i, total;
-
- total = end - start;
-
- sub_v3_v3v3(delta_p, p_end, p_start);
-
- prev = stk->points + start;
- next = stk->points + end;
-
- copy_v3_v3(pt1.p, p_start);
- copy_v3_v3(pt1.no, prev->no);
- pt1.mode = prev->mode;
- pt1.type = prev->type;
-
- copy_v3_v3(pt2.p, p_end);
- copy_v3_v3(pt2.no, next->no);
- pt2.mode = next->mode;
- pt2.type = next->type;
-
- sk_insertStrokePoint(stk, &pt1, start + 1); /* insert after start */
- sk_insertStrokePoint(stk, &pt2, end + 1); /* insert before end (since end was pushed back already) */
-
- for (i = 1; i < total; i++) {
- float delta = (float)i / (float)total;
- float *p = stk->points[start + 1 + i].p;
-
- mul_v3_v3fl(p, delta_p, delta);
- add_v3_v3(p, p_start);
- }
-}
-
-void sk_polygonizeStroke(SK_Stroke *stk, int start, int end)
-{
- int offset;
- int i;
-
- /* find first exact points outside of range */
- for (; start > 0; start--) {
- if (stk->points[start].type == PT_EXACT) {
- break;
- }
- }
-
- for (; end < stk->nb_points - 1; end++) {
- if (stk->points[end].type == PT_EXACT) {
- break;
- }
- }
-
- offset = start + 1;
-
- for (i = start + 1; i < end; i++) {
- if (stk->points[i].type == PT_EXACT) {
- if (offset != i) {
- memcpy(stk->points + offset, stk->points + i, sizeof(SK_Point));
- }
-
- offset++;
- }
- }
-
- /* some points were removes, move end of array */
- if (offset < end) {
- int size = stk->nb_points - end;
- memmove(stk->points + offset, stk->points + end, size * sizeof(SK_Point));
- stk->nb_points = offset + size;
- }
-}
-
-void sk_flattenStroke(SK_Stroke *stk, int start, int end)
-{
- float normal[3], distance[3];
- float limit;
- int i, total;
-
- total = end - start + 1;
-
- copy_v3_v3(normal, stk->points[start].no);
-
- sub_v3_v3v3(distance, stk->points[end].p, stk->points[start].p);
- project_v3_v3v3(normal, distance, normal);
- limit = normalize_v3(normal);
-
- for (i = 1; i < total - 1; i++) {
- float d = limit * i / total;
- float offset[3];
- float *p = stk->points[start + i].p;
-
- sub_v3_v3v3(distance, p, stk->points[start].p);
- project_v3_v3v3(distance, distance, normal);
-
- copy_v3_v3(offset, normal);
- mul_v3_fl(offset, d);
-
- sub_v3_v3(p, distance);
- add_v3_v3(p, offset);
- }
-}
-
-void sk_removeStroke(SK_Sketch *sketch, SK_Stroke *stk)
-{
- if (sketch->active_stroke == stk) {
- sketch->active_stroke = NULL;
- }
-
- BLI_remlink(&sketch->strokes, stk);
- sk_freeStroke(stk);
-}
-
-void sk_reverseStroke(SK_Stroke *stk)
-{
- SK_Point *old_points = stk->points;
- int i = 0;
-
- sk_allocStrokeBuffer(stk);
-
- for (i = 0; i < stk->nb_points; i++) {
- sk_copyPoint(stk->points + i, old_points + stk->nb_points - 1 - i);
- }
-
- MEM_freeN(old_points);
-}
-
-
-/* Ramer-Douglas-Peucker algorithm for line simplification */
-void sk_filterStroke(SK_Stroke *stk, int start, int end)
-{
- SK_Point *old_points = stk->points;
- int nb_points = stk->nb_points;
- char *marked = NULL;
- char work;
- int i;
-
- if (start == -1) {
- start = 0;
- end = stk->nb_points - 1;
- }
-
- sk_allocStrokeBuffer(stk);
- stk->nb_points = 0;
-
- /* adding points before range */
- for (i = 0; i < start; i++) {
- sk_appendStrokePoint(stk, old_points + i);
- }
-
- marked = MEM_callocN(nb_points, "marked array");
- marked[start] = 1;
- marked[end] = 1;
-
- work = 1;
-
- /* while still reducing */
- while (work) {
- int ls, le;
- work = 0;
-
- ls = start;
- le = start + 1;
-
- /* while not over interval */
- while (ls < end) {
- int max_i = 0;
- short v1[2];
- float max_dist = 16; /* more than 4 pixels */
-
- /* find the next marked point */
- while (marked[le] == 0) {
- le++;
- }
-
- /* perpendicular vector to ls-le */
- v1[1] = old_points[le].p2d[0] - old_points[ls].p2d[0];
- v1[0] = old_points[ls].p2d[1] - old_points[le].p2d[1];
-
-
- for (i = ls + 1; i < le; i++) {
- float mul;
- float dist;
- short v2[2];
-
- v2[0] = old_points[i].p2d[0] - old_points[ls].p2d[0];
- v2[1] = old_points[i].p2d[1] - old_points[ls].p2d[1];
-
- if (v2[0] == 0 && v2[1] == 0) {
- continue;
- }
-
- mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
-
- dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
-
- if (dist > max_dist) {
- max_dist = dist;
- max_i = i;
- }
- }
-
- if (max_i != 0) {
- work = 1;
- marked[max_i] = 1;
- }
-
- ls = le;
- le = ls + 1;
- }
- }
-
-
- /* adding points after range */
- for (i = start; i <= end; i++) {
- if (marked[i]) {
- sk_appendStrokePoint(stk, old_points + i);
- }
- }
-
- MEM_freeN(marked);
-
- /* adding points after range */
- for (i = end + 1; i < nb_points; i++) {
- sk_appendStrokePoint(stk, old_points + i);
- }
-
- MEM_freeN(old_points);
-
- sk_shrinkStrokeBuffer(stk);
-}
-
-
-void sk_filterLastContinuousStroke(SK_Stroke *stk)
-{
- int start, end;
-
- end = stk->nb_points - 1;
-
- for (start = end - 1; start > 0 && stk->points[start].type == PT_CONTINUOUS; start--) {
- /* nothing to do here*/
- }
-
- if (end - start > 1) {
- sk_filterStroke(stk, start, end);
- }
-}
-
-SK_Point *sk_lastStrokePoint(SK_Stroke *stk)
-{
- SK_Point *pt = NULL;
-
- if (stk->nb_points > 0) {
- pt = stk->points + (stk->nb_points - 1);
- }
-
- return pt;
-}
-
-void sk_endContinuousStroke(SK_Stroke *stk)
-{
- stk->points[stk->nb_points - 1].type = PT_EXACT;
-}
-
-void sk_updateNextPoint(SK_Sketch *sketch, SK_Stroke *stk)
-{
- if (stk) {
- memcpy(&(sketch->next_point), &(stk->points[stk->nb_points - 1]), sizeof(SK_Point));
- }
-}
-
-int sk_stroke_filtermval(SK_DrawData *dd)
-{
- int retval = 0;
- if (ABS(dd->mval[0] - dd->previous_mval[0]) + ABS(dd->mval[1] - dd->previous_mval[1]) > U.gp_manhattendist) {
- retval = 1;
- }
-
- return retval;
-}
-
-void sk_initDrawData(SK_DrawData *dd, const int mval[2])
-{
- dd->mval[0] = mval[0];
- dd->mval[1] = mval[1];
- dd->previous_mval[0] = -1;
- dd->previous_mval[1] = -1;
- dd->type = PT_EXACT;
-}
-
-
-void sk_deleteSelectedStrokes(SK_Sketch *sketch)
-{
- SK_Stroke *stk, *next;
-
- for (stk = sketch->strokes.first; stk; stk = next) {
- next = stk->next;
-
- if (stk->selected == 1) {
- sk_removeStroke(sketch, stk);
- }
- }
-}
-
-void sk_selectAllSketch(SK_Sketch *sketch, int mode)
-{
- SK_Stroke *stk = NULL;
-
- if (mode == -1) {
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- stk->selected = 0;
- }
- }
- else if (mode == 0) {
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- stk->selected = 1;
- }
- }
- else if (mode == 1) {
- int selected = 1;
-
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- selected &= stk->selected;
- }
-
- selected ^= 1;
-
- for (stk = sketch->strokes.first; stk; stk = stk->next) {
- stk->selected = selected;
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 150e8a129fe..4a403d337b3 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -54,6 +54,7 @@
#include "DNA_constraint_types.h"
#include "DNA_customdata_types.h"
#include "DNA_lamp_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
@@ -65,17 +66,17 @@
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_bvhutils.h"
-#include "BKE_cdderivedmesh.h"
#include "BKE_collision.h"
#include "BKE_colortools.h"
#include "BKE_constraint.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -84,6 +85,9 @@
#include "BKE_smoke.h"
#include "BKE_texture.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "RE_shader_ext.h"
#include "GPU_glew.h"
@@ -103,9 +107,9 @@
static ThreadMutex object_update_lock = BLI_MUTEX_INITIALIZER;
+struct Mesh;
struct Object;
struct Scene;
-struct DerivedMesh;
struct SmokeModifierData;
// timestep default value for nice appearance 0.1f
@@ -127,7 +131,7 @@ void smoke_initWaveletBlenderRNA(struct WTURBULENCE *UNUSED(wt), float *UNUSED(s
void smoke_initBlenderRNA(struct FLUID_3D *UNUSED(fluid), float *UNUSED(alpha), float *UNUSED(beta), float *UNUSED(dt_factor), float *UNUSED(vorticity),
int *UNUSED(border_colli), float *UNUSED(burning_rate), float *UNUSED(flame_smoke), float *UNUSED(flame_smoke_color),
float *UNUSED(flame_vorticity), float *UNUSED(flame_ignition_temp), float *UNUSED(flame_max_temp)) {}
-struct DerivedMesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Scene *UNUSED(scene), Object *UNUSED(ob), DerivedMesh *UNUSED(dm)) { return NULL; }
+struct Mesh *smokeModifier_do(SmokeModifierData *UNUSED(smd), Depsgraph *UNUSED(depsgraph), Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *UNUSED(me)) { return NULL; }
float smoke_get_velocity_at(struct Object *UNUSED(ob), float UNUSED(position[3]), float UNUSED(velocity[3])) { return 0.0f; }
#endif /* WITH_SMOKE */
@@ -192,20 +196,20 @@ static void smoke_pos_to_cell(SmokeDomainSettings *sds, float pos[3])
pos[2] *= 1.0f / sds->cell_size[2];
}
-/* set domain transformations and base resolution from object derivedmesh */
-static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *ob, DerivedMesh *dm, bool init_resolution)
+/* set domain transformations and base resolution from object mesh */
+static void smoke_set_domain_from_mesh(SmokeDomainSettings *sds, Object *ob, Mesh *me, bool init_resolution)
{
size_t i;
float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
float size[3];
- MVert *verts = dm->getVertArray(dm);
+ MVert *verts = me->mvert;
float scale = 0.0;
int res;
res = sds->maxres;
// get BB of domain
- for (i = 0; i < dm->getNumVerts(dm); i++)
+ for (i = 0; i < me->totvert; i++)
{
// min BB
min[0] = MIN2(min[0], verts[i].co[0]);
@@ -271,14 +275,14 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object *
sds->cell_size[2] /= (float)sds->base_res[2];
}
-static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
+static int smokeModifier_init(SmokeModifierData *smd, Object *ob, int scene_framenr, Mesh *me)
{
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
{
SmokeDomainSettings *sds = smd->domain;
int res[3];
- /* set domain dimensions from derivedmesh */
- smoke_set_domain_from_derivedmesh(sds, ob, dm, true);
+ /* set domain dimensions from mesh */
+ smoke_set_domain_from_mesh(sds, ob, me, true);
/* reset domain values */
zero_v3_int(sds->shift);
zero_v3(sds->shift_f);
@@ -302,7 +306,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene,
/* allocate fluid */
smoke_reallocate_fluid(sds, sds->dx, sds->res, 0);
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
/* allocate highres fluid */
if (sds->flags & MOD_SMOKE_HIGHRES) {
@@ -316,7 +320,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene,
}
else if ((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
{
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
return 1;
}
@@ -327,7 +331,7 @@ static int smokeModifier_init(SmokeModifierData *smd, Object *ob, Scene *scene,
smokeModifier_createType(smd);
}
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
return 1;
}
@@ -358,8 +362,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd)
MEM_freeN(smd->domain->effector_weights);
smd->domain->effector_weights = NULL;
- BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
- smd->domain->point_cache[0] = NULL;
+ if (!(smd->modifier.flag & eModifierFlag_SharedCaches)) {
+ BKE_ptcache_free_list(&(smd->domain->ptcaches[0]));
+ smd->domain->point_cache[0] = NULL;
+ }
if (smd->domain->coba) {
MEM_freeN(smd->domain->coba);
@@ -374,7 +380,7 @@ static void smokeModifier_freeFlow(SmokeModifierData *smd)
{
if (smd->flow)
{
- if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm);
+ if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh);
if (smd->flow->verts_old) MEM_freeN(smd->flow->verts_old);
MEM_freeN(smd->flow);
smd->flow = NULL;
@@ -396,9 +402,9 @@ static void smokeModifier_freeCollision(SmokeModifierData *smd)
}
}
- if (smd->coll->dm)
- smd->coll->dm->release(smd->coll->dm);
- smd->coll->dm = NULL;
+ if (smd->coll->mesh)
+ BKE_id_free(NULL, smd->coll->mesh);
+ smd->coll->mesh = NULL;
MEM_freeN(smd->coll);
smd->coll = NULL;
@@ -581,7 +587,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->flow->color[1] = 0.7f;
smd->flow->color[2] = 0.7f;
- smd->flow->dm = NULL;
+ smd->flow->mesh = NULL;
smd->flow->psys = NULL;
}
@@ -596,16 +602,12 @@ void smokeModifier_createType(struct SmokeModifierData *smd)
smd->coll->verts_old = NULL;
smd->coll->numverts = 0;
smd->coll->type = 0; // static obstacle
- smd->coll->dm = NULL;
-
-#ifdef USE_SMOKE_COLLISION_DM
- smd->coll->dm = NULL;
-#endif
+ smd->coll->mesh = NULL;
}
}
}
-void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifierData *tsmd)
+void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifierData *tsmd, const int flag)
{
tsmd->type = smd->type;
tsmd->time = smd->time;
@@ -613,80 +615,102 @@ void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifie
smokeModifier_createType(tsmd);
if (tsmd->domain) {
- tsmd->domain->fluid_group = smd->domain->fluid_group;
- tsmd->domain->coll_group = smd->domain->coll_group;
-
- tsmd->domain->adapt_margin = smd->domain->adapt_margin;
- tsmd->domain->adapt_res = smd->domain->adapt_res;
- tsmd->domain->adapt_threshold = smd->domain->adapt_threshold;
-
- tsmd->domain->alpha = smd->domain->alpha;
- tsmd->domain->beta = smd->domain->beta;
- tsmd->domain->amplify = smd->domain->amplify;
- tsmd->domain->maxres = smd->domain->maxres;
- tsmd->domain->flags = smd->domain->flags;
- tsmd->domain->highres_sampling = smd->domain->highres_sampling;
- tsmd->domain->viewsettings = smd->domain->viewsettings;
- tsmd->domain->noise = smd->domain->noise;
- tsmd->domain->diss_speed = smd->domain->diss_speed;
- tsmd->domain->strength = smd->domain->strength;
-
- tsmd->domain->border_collisions = smd->domain->border_collisions;
- tsmd->domain->vorticity = smd->domain->vorticity;
- tsmd->domain->time_scale = smd->domain->time_scale;
-
- tsmd->domain->burning_rate = smd->domain->burning_rate;
- tsmd->domain->flame_smoke = smd->domain->flame_smoke;
- tsmd->domain->flame_vorticity = smd->domain->flame_vorticity;
- tsmd->domain->flame_ignition = smd->domain->flame_ignition;
- tsmd->domain->flame_max_temp = smd->domain->flame_max_temp;
- copy_v3_v3(tsmd->domain->flame_smoke_color, smd->domain->flame_smoke_color);
-
- MEM_freeN(tsmd->domain->effector_weights);
- tsmd->domain->effector_weights = MEM_dupallocN(smd->domain->effector_weights);
- tsmd->domain->openvdb_comp = smd->domain->openvdb_comp;
- tsmd->domain->data_depth = smd->domain->data_depth;
- tsmd->domain->cache_file_format = smd->domain->cache_file_format;
-
- tsmd->domain->slice_method = smd->domain->slice_method;
- tsmd->domain->axis_slice_method = smd->domain->axis_slice_method;
- tsmd->domain->slice_per_voxel = smd->domain->slice_per_voxel;
- tsmd->domain->slice_depth = smd->domain->slice_depth;
- tsmd->domain->slice_axis = smd->domain->slice_axis;
- tsmd->domain->draw_velocity = smd->domain->draw_velocity;
- tsmd->domain->vector_draw_type = smd->domain->vector_draw_type;
- tsmd->domain->vector_scale = smd->domain->vector_scale;
+ SmokeDomainSettings *tsds = tsmd->domain;
+ SmokeDomainSettings *sds = smd->domain;
- if (smd->domain->coba) {
- tsmd->domain->coba = MEM_dupallocN(smd->domain->coba);
+ BKE_ptcache_free_list(&(tsds->ptcaches[0]));
+
+ if (flag & LIB_ID_CREATE_NO_MAIN) {
+ /* Share the cache with the original object's modifier. */
+ tsmd->modifier.flag |= eModifierFlag_SharedCaches;
+ tsds->point_cache[0] = sds->point_cache[0];
+ tsds->ptcaches[0] = sds->ptcaches[0];
+ }
+ else {
+ tsds->point_cache[0] = BKE_ptcache_copy_list(&(tsds->ptcaches[0]), &(sds->ptcaches[0]), flag);
+ }
+
+ tsds->fluid_group = sds->fluid_group;
+ tsds->coll_group = sds->coll_group;
+
+ tsds->adapt_margin = sds->adapt_margin;
+ tsds->adapt_res = sds->adapt_res;
+ tsds->adapt_threshold = sds->adapt_threshold;
+
+ tsds->alpha = sds->alpha;
+ tsds->beta = sds->beta;
+ tsds->amplify = sds->amplify;
+ tsds->maxres = sds->maxres;
+ tsds->flags = sds->flags;
+ tsds->highres_sampling = sds->highres_sampling;
+ tsds->viewsettings = sds->viewsettings;
+ tsds->noise = sds->noise;
+ tsds->diss_speed = sds->diss_speed;
+ tsds->strength = sds->strength;
+
+ tsds->border_collisions = sds->border_collisions;
+ tsds->vorticity = sds->vorticity;
+ tsds->time_scale = sds->time_scale;
+
+ tsds->burning_rate = sds->burning_rate;
+ tsds->flame_smoke = sds->flame_smoke;
+ tsds->flame_vorticity = sds->flame_vorticity;
+ tsds->flame_ignition = sds->flame_ignition;
+ tsds->flame_max_temp = sds->flame_max_temp;
+ copy_v3_v3(tsds->flame_smoke_color, sds->flame_smoke_color);
+
+ MEM_freeN(tsds->effector_weights);
+ tsds->effector_weights = MEM_dupallocN(sds->effector_weights);
+ tsds->openvdb_comp = sds->openvdb_comp;
+ tsds->data_depth = sds->data_depth;
+ tsds->cache_file_format = sds->cache_file_format;
+
+ tsds->display_thickness = sds->display_thickness;
+ tsds->slice_method = sds->slice_method;
+ tsds->axis_slice_method = sds->axis_slice_method;
+ tsds->slice_per_voxel = sds->slice_per_voxel;
+ tsds->slice_depth = sds->slice_depth;
+ tsds->slice_axis = sds->slice_axis;
+ tsds->interp_method = sds->interp_method;
+ tsds->draw_velocity = sds->draw_velocity;
+ tsds->vector_draw_type = sds->vector_draw_type;
+ tsds->vector_scale = sds->vector_scale;
+
+ tsds->use_coba = sds->use_coba;
+ tsds->coba_field = sds->coba_field;
+ if (sds->coba) {
+ tsds->coba = MEM_dupallocN(sds->coba);
}
}
else if (tsmd->flow) {
- tsmd->flow->psys = smd->flow->psys;
- tsmd->flow->noise_texture = smd->flow->noise_texture;
-
- tsmd->flow->vel_multi = smd->flow->vel_multi;
- tsmd->flow->vel_normal = smd->flow->vel_normal;
- tsmd->flow->vel_random = smd->flow->vel_random;
-
- tsmd->flow->density = smd->flow->density;
- copy_v3_v3(tsmd->flow->color, smd->flow->color);
- tsmd->flow->fuel_amount = smd->flow->fuel_amount;
- tsmd->flow->temp = smd->flow->temp;
- tsmd->flow->volume_density = smd->flow->volume_density;
- tsmd->flow->surface_distance = smd->flow->surface_distance;
- tsmd->flow->particle_size = smd->flow->particle_size;
- tsmd->flow->subframes = smd->flow->subframes;
-
- tsmd->flow->texture_size = smd->flow->texture_size;
- tsmd->flow->texture_offset = smd->flow->texture_offset;
- BLI_strncpy(tsmd->flow->uvlayer_name, smd->flow->uvlayer_name, sizeof(tsmd->flow->uvlayer_name));
- tsmd->flow->vgroup_density = smd->flow->vgroup_density;
-
- tsmd->flow->type = smd->flow->type;
- tsmd->flow->source = smd->flow->source;
- tsmd->flow->texture_type = smd->flow->texture_type;
- tsmd->flow->flags = smd->flow->flags;
+ SmokeFlowSettings *tsfs = tsmd->flow;
+ SmokeFlowSettings *sfs = smd->flow;
+
+ tsfs->psys = sfs->psys;
+ tsfs->noise_texture = sfs->noise_texture;
+
+ tsfs->vel_multi = sfs->vel_multi;
+ tsfs->vel_normal = sfs->vel_normal;
+ tsfs->vel_random = sfs->vel_random;
+
+ tsfs->density = sfs->density;
+ copy_v3_v3(tsfs->color, sfs->color);
+ tsfs->fuel_amount = sfs->fuel_amount;
+ tsfs->temp = sfs->temp;
+ tsfs->volume_density = sfs->volume_density;
+ tsfs->surface_distance = sfs->surface_distance;
+ tsfs->particle_size = sfs->particle_size;
+ tsfs->subframes = sfs->subframes;
+
+ tsfs->texture_size = sfs->texture_size;
+ tsfs->texture_offset = sfs->texture_offset;
+ BLI_strncpy(tsfs->uvlayer_name, sfs->uvlayer_name, sizeof(tsfs->uvlayer_name));
+ tsfs->vgroup_density = sfs->vgroup_density;
+
+ tsfs->type = sfs->type;
+ tsfs->source = sfs->source;
+ tsfs->texture_type = sfs->texture_type;
+ tsfs->flags = sfs->flags;
}
else if (tsmd->coll) {
/* leave it as initialized, collision settings is mostly caches */
@@ -695,17 +719,17 @@ void smokeModifier_copy(const struct SmokeModifierData *smd, struct SmokeModifie
#ifdef WITH_SMOKE
-// forward decleration
-static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene);
+// forward declaration
+static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer);
static float calc_voxel_transp(float *result, float *input, int res[3], int *pixel, float *tRay, float correct);
-static int get_lamp(Scene *scene, float *light)
+static int get_lamp(ViewLayer *view_layer, float *light)
{
Base *base_tmp = NULL;
int found_lamp = 0;
// try to find a lamp, preferably local
- for (base_tmp = scene->base.first; base_tmp; base_tmp = base_tmp->next) {
+ for (base_tmp = FIRSTBASE(view_layer); base_tmp; base_tmp = base_tmp->next) {
if (base_tmp->object->type == OB_LAMP) {
Lamp *la = base_tmp->object->data;
@@ -741,7 +765,7 @@ typedef struct ObstaclesFromDMData {
int *num_obstacles;
} ObstaclesFromDMData;
-static void obstacles_from_derivedmesh_task_cb(
+static void obstacles_from_mesh_task_cb(
void *__restrict userdata,
const int z,
const ParallelRangeTLS *__restrict UNUSED(tls))
@@ -798,13 +822,13 @@ static void obstacles_from_derivedmesh_task_cb(
}
}
-static void obstacles_from_derivedmesh(
+static void obstacles_from_mesh(
Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs,
unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt)
{
- if (!scs->dm) return;
+ if (!scs->mesh) return;
{
- DerivedMesh *dm = NULL;
+ Mesh *me = NULL;
MVert *mvert = NULL;
const MLoopTri *looptri;
const MLoop *mloop;
@@ -814,12 +838,12 @@ static void obstacles_from_derivedmesh(
float *vert_vel = NULL;
bool has_velocity = false;
- dm = CDDM_copy(scs->dm);
- CDDM_calc_normals(dm);
- mvert = dm->getVertArray(dm);
- mloop = dm->getLoopArray(dm);
- looptri = dm->getLoopTriArray(dm);
- numverts = dm->getNumVerts(dm);
+ me = BKE_mesh_copy_for_eval(scs->mesh, true);
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ mloop = me->mloop;
+ looptri = BKE_mesh_runtime_looptri_ensure(me);
+ numverts = me->totvert;
// DG TODO
// if (scs->type > SM_COLL_STATIC)
@@ -866,7 +890,7 @@ static void obstacles_from_derivedmesh(
copy_v3_v3(&scs->verts_old[i * 3], co);
}
- if (bvhtree_from_mesh_get(&treeData, dm, BVHTREE_FROM_LOOPTRI, 4)) {
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
ObstaclesFromDMData data = {
.sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri,
.tree = &treeData, .obstacle_map = obstacle_map,
@@ -879,19 +903,19 @@ static void obstacles_from_derivedmesh(
settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(sds->res_min[2], sds->res_max[2],
&data,
- obstacles_from_derivedmesh_task_cb,
+ obstacles_from_mesh_task_cb,
&settings);
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
- dm->release(dm);
+ BKE_id_free(NULL, me);
if (vert_vel) MEM_freeN(vert_vel);
}
}
/* Animated obstacles: dx_step = ((x_new - x_old) / totalsteps) * substep */
-static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt,
+static void update_obstacles(Depsgraph *depsgraph, Object *ob, SmokeDomainSettings *sds, float dt,
int UNUSED(substep), int UNUSED(totalsteps))
{
Object **collobjs = NULL;
@@ -931,7 +955,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
}
- collobjs = get_collisionobjects(scene, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
+ collobjs = BKE_collision_objects_create(depsgraph, ob, sds->coll_group, &numcollobj, eModifierType_Smoke);
// update obstacle tags in cells
for (collIndex = 0; collIndex < numcollobj; collIndex++)
@@ -944,12 +968,11 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
{
SmokeCollSettings *scs = smd2->coll;
- obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
+ obstacles_from_mesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
}
}
- if (collobjs)
- MEM_freeN(collobjs);
+ BKE_collision_objects_free(collobjs);
/* obstacle cells should not contain any velocity from the smoke simulation */
for (z = 0; z < sds->res[0] * sds->res[1] * sds->res[2]; z++)
@@ -1264,7 +1287,7 @@ static void emit_from_particles_task_cb(
}
static void emit_from_particles(
- Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Scene *scene, float dt)
+ Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, Depsgraph *depsgraph, Scene *scene, float dt)
{
if (sfs && sfs->psys && sfs->psys->part && ELEM(sfs->psys->part->type, PART_EMITTER, PART_FLUID)) // is particle system selected
{
@@ -1283,6 +1306,7 @@ static void emit_from_particles(
int hires_multiplier = 1;
KDTree *tree = NULL;
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = flow_ob;
sim.psys = psys;
@@ -1335,7 +1359,7 @@ static void emit_from_particles(
continue;
}
- state.time = BKE_scene_frame_get(scene); /* use scene time */
+ state.time = DEG_get_ctime(depsgraph); /* use depsgraph time */
if (psys_get_particle_state(&sim, p, &state, 0) == 0)
continue;
@@ -1436,7 +1460,7 @@ static void emit_from_particles(
}
}
-static void sample_derivedmesh(
+static void sample_mesh(
SmokeFlowSettings *sfs,
const MVert *mvert, const MLoop *mloop, const MLoopTri *mlooptri, const MLoopUV *mloopuv,
float *influence_map, float *velocity_map, int index, const int base_res[3], float flow_center[3],
@@ -1593,7 +1617,7 @@ typedef struct EmitFromDMData {
int *min, *max, *res;
} EmitFromDMData;
-static void emit_from_derivedmesh_task_cb(
+static void emit_from_mesh_task_cb(
void *__restrict userdata,
const int z,
const ParallelRangeTLS *__restrict UNUSED(tls))
@@ -1615,7 +1639,7 @@ static void emit_from_derivedmesh_task_cb(
lx - em->min[0], em->res[0], ly - em->min[1], em->res[1], lz - em->min[2]);
const float ray_start[3] = {((float)lx) + 0.5f, ((float)ly) + 0.5f, ((float)lz) + 0.5f};
- sample_derivedmesh(
+ sample_mesh(
data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
em->influence, em->velocity, index, data->sds->base_res, data->flow_center,
data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
@@ -1633,7 +1657,7 @@ static void emit_from_derivedmesh_task_cb(
x - data->min[0], data->res[0], y - data->min[1], data->res[1], z - data->min[2]);
const float ray_start[3] = {lx + 0.5f * data->hr, ly + 0.5f * data->hr, lz + 0.5f * data->hr};
- sample_derivedmesh(
+ sample_mesh(
data->sfs, data->mvert, data->mloop, data->mlooptri, data->mloopuv,
em->influence_high, NULL, index, data->sds->base_res, data->flow_center,
data->tree, ray_start, data->vert_vel, data->has_velocity, data->defgrp_index, data->dvert,
@@ -1644,14 +1668,13 @@ static void emit_from_derivedmesh_task_cb(
}
}
-static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
+static void emit_from_mesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
{
- if (sfs->dm) {
- DerivedMesh *dm;
+ if (sfs->mesh) {
+ Mesh *me;
int defgrp_index = sfs->vgroup_density - 1;
MDeformVert *dvert = NULL;
MVert *mvert = NULL;
- MVert *mvert_orig = NULL;
const MLoopTri *mlooptri = NULL;
const MLoopUV *mloopuv = NULL;
const MLoop *mloop = NULL;
@@ -1664,19 +1687,24 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
int min[3], max[3], res[3];
int hires_multiplier = 1;
- /* copy derivedmesh for thread safety because we modify it,
+ /* copy mesh for thread safety because we modify it,
* main issue is its VertArray being modified, then replaced and freed
*/
- dm = CDDM_copy(sfs->dm);
+ me = BKE_mesh_copy_for_eval(sfs->mesh, true);
+
+ /* Duplicate vertices to modify. */
+ if (me->mvert) {
+ me->mvert = MEM_dupallocN(me->mvert);
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ }
- CDDM_calc_normals(dm);
- mvert = dm->getVertArray(dm);
- mvert_orig = dm->dupVertArray(dm); /* copy original mvert and restore when done */
- numOfVerts = dm->getNumVerts(dm);
- dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
- mloopuv = CustomData_get_layer_named(&dm->loopData, CD_MLOOPUV, sfs->uvlayer_name);
- mloop = dm->getLoopArray(dm);
- mlooptri = dm->getLoopTriArray(dm);
+ BKE_mesh_ensure_normals(me);
+ mvert = me->mvert;
+ numOfVerts = me->totvert;
+ dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, sfs->uvlayer_name);
+ mloop = me->mloop;
+ mlooptri = BKE_mesh_runtime_looptri_ensure(me);
if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY) {
vert_vel = MEM_callocN(sizeof(float) * numOfVerts * 3, "smoke_flow_velocity");
@@ -1691,7 +1719,7 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
}
}
- /* Transform dm vertices to
+ /* Transform mesh vertices to
* domain grid space for fast lookups */
for (i = 0; i < numOfVerts; i++) {
float n[3];
@@ -1737,7 +1765,7 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
res[i] = em->res[i] * hires_multiplier;
}
- if (bvhtree_from_mesh_get(&treeData, dm, BVHTREE_FROM_LOOPTRI, 4)) {
+ if (BKE_bvhtree_from_mesh_get(&treeData, me, BVHTREE_FROM_LOOPTRI, 4)) {
const float hr = 1.0f / ((float)hires_multiplier);
EmitFromDMData data = {
@@ -1754,23 +1782,20 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(min[2], max[2],
&data,
- emit_from_derivedmesh_task_cb,
+ emit_from_mesh_task_cb,
&settings);
}
/* free bvh tree */
free_bvhtree_from_mesh(&treeData);
- /* restore original mverts */
- CustomData_set_layer(&dm->vertData, CD_MVERT, mvert_orig);
- if (mvert) {
- MEM_freeN(mvert);
- }
if (vert_vel) {
MEM_freeN(vert_vel);
}
- dm->needsFree = 1;
- dm->release(dm);
+ if (me->mvert) {
+ MEM_freeN(me->mvert);
+ }
+ BKE_id_free(NULL, me);
}
}
@@ -2107,7 +2132,7 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value
}
static void update_flowsfluids(
- Main *bmain, EvaluationContext *eval_ctx, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
+ Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float dt)
{
Object **flowobjs = NULL;
EmissionMap *emaps = NULL;
@@ -2149,7 +2174,7 @@ static void update_flowsfluids(
sds->p1[2] = sds->p0[2] + sds->cell_size[2] * sds->base_res[2];
}
- flowobjs = get_collisionobjects(scene, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
+ flowobjs = BKE_collision_objects_create(depsgraph, ob, sds->fluid_group, &numflowobj, eModifierType_Smoke);
/* init emission maps for each flow */
emaps = MEM_callocN(sizeof(struct EmissionMap) * numflowobj, "smoke_flow_maps");
@@ -2171,21 +2196,25 @@ static void update_flowsfluids(
/* just sample flow directly to emission map if no subframes */
if (!subframes) {
if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
- emit_from_particles(collob, sds, sfs, em, scene, dt);
+ emit_from_particles(collob, sds, sfs, em, depsgraph, scene, dt);
}
else {
- emit_from_derivedmesh(collob, sds, sfs, em, dt);
+ emit_from_mesh(collob, sds, sfs, em, dt);
}
}
/* sample subframes */
else {
- int scene_frame = scene->r.cfra;
+#if 0
+ int scene_frame = (int)DEG_get_ctime(depsgraph);
+#endif
// float scene_subframe = scene->r.subframe; // UNUSED
int subframe;
for (subframe = 0; subframe <= subframes; subframe++) {
EmissionMap em_temp = {NULL};
float sample_size = 1.0f / (float)(subframes+1);
+#if 0
float prev_frame_pos = sample_size * (float)(subframe+1);
+#endif
float sdt = dt * sample_size;
int hires_multiplier = 1;
@@ -2193,6 +2222,8 @@ static void update_flowsfluids(
hires_multiplier = sds->amplify + 1;
}
+ /* TODO: setting the scene frame no longer works with the new depsgraph. */
+#if 0
/* set scene frame to match previous frame + subframe
* or use current frame for last sample */
if (subframe < subframes) {
@@ -2203,10 +2234,11 @@ static void update_flowsfluids(
scene->r.cfra = scene_frame;
scene->r.subframe = 0.0f;
}
+#endif
if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
/* emit_from_particles() updates timestep internally */
- emit_from_particles(collob, sds, sfs, &em_temp, scene, sdt);
+ emit_from_particles(collob, sds, sfs, &em_temp, depsgraph, scene, sdt);
if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
hires_multiplier = 1;
}
@@ -2214,13 +2246,11 @@ static void update_flowsfluids(
else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
/* update flow object frame */
BLI_mutex_lock(&object_update_lock);
- BKE_object_modifier_update_subframe(
- bmain, eval_ctx, scene, collob,
- true, 5, BKE_scene_frame_get(scene), eModifierType_Smoke);
+ BKE_object_modifier_update_subframe(depsgraph, scene, collob, true, 5, DEG_get_ctime(depsgraph), eModifierType_Smoke);
BLI_mutex_unlock(&object_update_lock);
/* apply flow */
- emit_from_derivedmesh(collob, sds, sfs, &em_temp, sdt);
+ emit_from_mesh(collob, sds, sfs, &em_temp, sdt);
}
/* combine emission maps */
@@ -2452,8 +2482,7 @@ static void update_flowsfluids(
}
}
- if (flowobjs)
- MEM_freeN(flowobjs);
+ BKE_collision_objects_free(flowobjs);
if (emaps)
MEM_freeN(emaps);
}
@@ -2512,7 +2541,7 @@ static void update_effectors_task_cb(
mul_m4_v3(sds->obmat, voxelCenter);
pd_point_from_loc(data->scene, voxelCenter, vel, index, &epoint);
- pdDoEffectors(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
+ BKE_effectors_apply(data->effectors, NULL, sds->effector_weights, &epoint, retvel, NULL);
/* convert retvel to local space */
mag = len_v3(retvel);
@@ -2528,12 +2557,12 @@ static void update_effectors_task_cb(
}
}
-static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
+static void update_effectors(Depsgraph *depsgraph, Scene *scene, Object *ob, SmokeDomainSettings *sds, float UNUSED(dt))
{
ListBase *effectors;
/* make sure smoke flow influence is 0.0f */
sds->effector_weights->weight[PFIELD_SMOKEFLOW] = 0.0f;
- effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights, true);
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, sds->effector_weights);
if (effectors) {
// precalculate wind forces
@@ -2560,12 +2589,12 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds,
&settings);
}
- pdEndEffectors(&effectors);
+ BKE_effectors_free(effectors);
}
static void step(
- Main *bmain, EvaluationContext *eval_ctx,
- Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh *domain_dm, float fps)
+ Depsgraph *depsgraph,
+ Scene *scene, Object *ob, SmokeModifierData *smd, Mesh *domain_me, float fps)
{
SmokeDomainSettings *sds = smd->domain;
/* stability values copied from wturbulence.cpp */
@@ -2581,19 +2610,10 @@ static void step(
float gravity[3] = {0.0f, 0.0f, -1.0f};
float gravity_mag;
-#if 0 /* UNUSED */
- /* get max velocity and lower the dt value if it is too high */
- size_t size = sds->res[0] * sds->res[1] * sds->res[2];
- float *velX = smoke_get_velocity_x(sds->fluid);
- float *velY = smoke_get_velocity_y(sds->fluid);
- float *velZ = smoke_get_velocity_z(sds->fluid);
- size_t i;
-#endif
-
/* update object state */
invert_m4_m4(sds->imat, ob->obmat);
copy_m4_m4(sds->obmat, ob->obmat);
- smoke_set_domain_from_derivedmesh(sds, ob, domain_dm, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
+ smoke_set_domain_from_mesh(sds, ob, domain_me, (sds->flags & MOD_SMOKE_ADAPTIVE_DOMAIN) != 0);
/* use global gravity if enabled */
if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
@@ -2612,14 +2632,6 @@ static void step(
// maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel
maxVel = (sds->dx * 5.0f);
-#if 0
- for (i = 0; i < size; i++) {
- float vtemp = (velX[i] * velX[i] + velY[i] * velY[i] + velZ[i] * velZ[i]);
- if (vtemp > maxVelMag)
- maxVelMag = vtemp;
- }
-#endif
-
maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale;
totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */
totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps;
@@ -2635,19 +2647,19 @@ static void step(
for (substep = 0; substep < totalSubsteps; substep++)
{
// calc animated obstacle velocities
- update_flowsfluids(bmain, eval_ctx, scene, ob, sds, dtSubdiv);
- update_obstacles(scene, ob, sds, dtSubdiv, substep, totalSubsteps);
+ update_flowsfluids(depsgraph, scene, ob, sds, dtSubdiv);
+ update_obstacles(depsgraph, ob, sds, dtSubdiv, substep, totalSubsteps);
if (sds->total_cells > 1) {
- update_effectors(scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
+ update_effectors(depsgraph, scene, ob, sds, dtSubdiv); // DG TODO? problem --> uses forces instead of velocity, need to check how they need to be changed with variable dt
smoke_step(sds->fluid, gravity, dtSubdiv);
}
}
}
-static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
+static Mesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
{
- DerivedMesh *result;
+ Mesh *result;
MVert *mverts;
MPoly *mpolys;
MLoop *mloops;
@@ -2669,11 +2681,10 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
num_faces = 0;
}
- result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces);
- mverts = CDDM_get_verts(result);
- mpolys = CDDM_get_polys(result);
- mloops = CDDM_get_loops(result);
-
+ result = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 4, num_faces);
+ mverts = result->mvert;
+ mpolys = result->mpoly;
+ mloops = result->mloop;
if (num_verts) {
/* volume bounds */
@@ -2726,48 +2737,49 @@ static DerivedMesh *createDomainGeometry(SmokeDomainSettings *sds, Object *ob)
}
}
-
- CDDM_calc_edges(result);
- result->dirty |= DM_DIRTY_NORMALS;
+ BKE_mesh_calc_edges(result, false, false);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
}
static void smokeModifier_process(
- Main *bmain, EvaluationContext *eval_ctx, SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+ SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
+ const int scene_framenr = (int)DEG_get_ctime(depsgraph);
+
if ((smd->type & MOD_SMOKE_TYPE_FLOW))
{
- if (scene->r.cfra >= smd->time)
- smokeModifier_init(smd, ob, scene, dm);
+ if (scene_framenr >= smd->time)
+ smokeModifier_init(smd, ob, scene_framenr, me);
- if (smd->flow->dm) smd->flow->dm->release(smd->flow->dm);
- smd->flow->dm = CDDM_copy(dm);
+ if (smd->flow->mesh) BKE_id_free(NULL, smd->flow->mesh);
+ smd->flow->mesh = BKE_mesh_copy_for_eval(me, false);
- if (scene->r.cfra > smd->time)
+ if (scene_framenr > smd->time)
{
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
}
- else if (scene->r.cfra < smd->time)
+ else if (scene_framenr < smd->time)
{
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
smokeModifier_reset_ex(smd, false);
}
}
else if (smd->type & MOD_SMOKE_TYPE_COLL)
{
- if (scene->r.cfra >= smd->time)
- smokeModifier_init(smd, ob, scene, dm);
+ if (scene_framenr >= smd->time)
+ smokeModifier_init(smd, ob, scene_framenr, me);
if (smd->coll)
{
- if (smd->coll->dm)
- smd->coll->dm->release(smd->coll->dm);
+ if (smd->coll->mesh)
+ BKE_id_free(NULL, smd->coll->mesh);
- smd->coll->dm = CDDM_copy(dm);
+ smd->coll->mesh = BKE_mesh_copy_for_eval(me, false);
}
- smd->time = scene->r.cfra;
- if (scene->r.cfra < smd->time)
+ smd->time = scene_framenr;
+ if (scene_framenr < smd->time)
{
smokeModifier_reset_ex(smd, false);
}
@@ -2780,9 +2792,7 @@ static void smokeModifier_process(
int startframe, endframe, framenr;
float timescale;
- framenr = scene->r.cfra;
-
- //printf("time: %d\n", scene->r.cfra);
+ framenr = scene_framenr;
cache = sds->point_cache[0];
BKE_ptcache_id_from_smoke(&pid, ob, smd);
@@ -2803,10 +2813,10 @@ static void smokeModifier_process(
CLAMP(framenr, startframe, endframe);
/* If already viewing a pre/after frame, no need to reload */
- if ((smd->time == framenr) && (framenr != scene->r.cfra))
+ if ((smd->time == framenr) && (framenr != scene_framenr))
return;
- if (smokeModifier_init(smd, ob, scene, dm) == 0)
+ if (smokeModifier_init(smd, ob, scene_framenr, me) == 0)
{
printf("bad smokeModifier_init\n");
return;
@@ -2814,7 +2824,7 @@ static void smokeModifier_process(
/* only calculate something when we advanced a single frame */
/* don't simulate if viewing start frame, but scene frame is not real start frame */
- bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene->r.cfra);
+ bool can_simulate = (framenr == (int)smd->time + 1) && (framenr == scene_framenr);
/* try to read from cache */
if (BKE_ptcache_read(&pid, (float)framenr, can_simulate) == PTCACHE_READ_EXACT) {
@@ -2836,7 +2846,7 @@ static void smokeModifier_process(
}
// set new time
- smd->time = scene->r.cfra;
+ smd->time = scene_framenr;
/* do simulation */
@@ -2854,11 +2864,11 @@ static void smokeModifier_process(
}
- step(bmain, eval_ctx, scene, ob, smd, dm, scene->r.frs_sec / scene->r.frs_sec_base);
+ step(depsgraph, scene, ob, smd, me, scene->r.frs_sec / scene->r.frs_sec_base);
}
// create shadows before writing cache so they get stored
- smoke_calc_transparency(sds, scene);
+ smoke_calc_transparency(sds, DEG_get_evaluated_view_layer(depsgraph));
if (sds->wt && sds->total_cells > 1) {
smoke_turbulence_step(sds->wt, sds->fluid);
@@ -2875,14 +2885,14 @@ static void smokeModifier_process(
}
}
-struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm)
+struct Mesh *smokeModifier_do(
+ SmokeModifierData *smd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
/* lock so preview render does not read smoke data while it gets modified */
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
BLI_rw_mutex_lock(smd->domain->fluid_mutex, THREAD_LOCK_WRITE);
- /* Ugly G.main, hopefully won't be needed anymore in 2.8 */
- smokeModifier_process(G.main, G.main->eval_ctx , smd, scene, ob, dm);
+ smokeModifier_process(smd, depsgraph, scene, ob, me);
if ((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain)
BLI_rw_mutex_unlock(smd->domain->fluid_mutex);
@@ -2895,7 +2905,7 @@ struct DerivedMesh *smokeModifier_do(SmokeModifierData *smd, Scene *scene, Objec
return createDomainGeometry(smd->domain, ob);
}
else {
- return CDDM_copy(dm);
+ return BKE_mesh_copy_for_eval(me, false);
}
}
@@ -2997,7 +3007,7 @@ static void bresenham_linie_3D(int x1, int y1, int z1, int x2, int y2, int z2, f
cb(result, input, res, pixel, tRay, correct);
}
-static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene)
+static void smoke_calc_transparency(SmokeDomainSettings *sds, ViewLayer *view_layer)
{
float bv[6] = {0};
float light[3];
@@ -3005,7 +3015,7 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene)
float *density = smoke_get_density(sds->fluid);
float correct = -7.0f * sds->dx;
- if (!get_lamp(scene, light)) return;
+ if (!get_lamp(view_layer, light)) return;
/* convert light pos to sim cell space */
mul_m4_v3(sds->imat, light);
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index a2f2819d132..e3bd6f9860f 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -55,13 +55,13 @@
#include "MEM_guardedalloc.h"
/* types */
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_lattice_types.h"
+#include "DNA_collection_types.h"
#include "DNA_curve_types.h"
-#include "DNA_mesh_types.h"
+#include "DNA_lattice_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_group_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -69,9 +69,12 @@
#include "BLI_ghash.h"
#include "BLI_threads.h"
+#include "BKE_collection.h"
+#include "BKE_collision.h"
#include "BKE_curve.h"
#include "BKE_effect.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_modifier.h"
#include "BKE_softbody.h"
#include "BKE_pointcache.h"
@@ -79,6 +82,9 @@
#include "BKE_mesh.h"
#include "BKE_scene.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "PIL_time.h"
/* callbacks for errors and interrupts and some goo */
@@ -132,7 +138,7 @@ typedef struct SB_thread_context {
float timenow;
int ifirst;
int ilast;
- ListBase *do_effector;
+ ListBase *effectors;
int do_deflector;
float fieldfactor;
float windfactor;
@@ -508,39 +514,24 @@ static void ccd_build_deflector_hash_single(GHash *hash, Object *ob)
}
/**
- * \note group overrides scene when not NULL.
+ * \note collection overrides scene when not NULL.
*/
-static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
+static void ccd_build_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash)
{
- Object *ob;
-
if (!hash) return;
- if (group) {
- /* Explicit collision group */
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- ob = go->ob;
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision);
- if (ob == vertexowner || ob->type != OB_MESH)
- continue;
+ for (int i = 0; i < numobjects; i++) {
+ Object *ob = objects[i];
+ if (ob->type == OB_MESH) {
ccd_build_deflector_hash_single(hash, ob);
}
}
- else {
- for (Base *base = scene->base.first; base; base = base->next) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) {
- ob= base->object;
- if ((vertexowner) && (ob == vertexowner)) {
- /* if vertexowner is given we don't want to check collision with owner object */
- continue;
- }
- ccd_build_deflector_hash_single(hash, ob);
- }
- }
- }
+ BKE_collision_objects_free(objects);
}
static void ccd_update_deflector_hash_single(GHash *hash, Object *ob)
@@ -554,42 +545,26 @@ static void ccd_update_deflector_hash_single(GHash *hash, Object *ob)
}
/**
- * \note group overrides scene when not NULL.
+ * \note collection overrides scene when not NULL.
*/
-static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertexowner, GHash *hash)
+static void ccd_update_deflector_hash(Depsgraph *depsgraph, Collection *collection, Object *vertexowner, GHash *hash)
{
- Object *ob;
-
if ((!hash) || (!vertexowner)) return;
- if (group) {
- /* Explicit collision group */
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- ob = go->ob;
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, vertexowner, collection, &numobjects, eModifierType_Collision);
- if (ob == vertexowner || ob->type != OB_MESH)
- continue;
+ for (int i = 0; i < numobjects; i++) {
+ Object *ob = objects[i];
+ if (ob->type == OB_MESH) {
ccd_update_deflector_hash_single(hash, ob);
}
}
- else {
- for (Base *base = scene->base.first; base; base = base->next) {
- /*Only proceed for mesh object in same layer */
- if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) {
- ob= base->object;
- if (ob == vertexowner) {
- /* if vertexowner is given we don't want to check collision with owner object */
- continue;
- }
- ccd_update_deflector_hash_single(hash, ob);
- }
- }
- }
+ BKE_collision_objects_free(objects);
}
-
/*--- collider caching and dicing ---*/
@@ -975,37 +950,21 @@ static void free_softbody_intern(SoftBody *sb)
/* +++ dependency information functions*/
/**
- * \note group overrides scene when not NULL.
+ * \note collection overrides scene when not NULL.
*/
-static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer)
+static int query_external_colliders(Depsgraph *depsgraph, Collection *collection)
{
- if (group) {
- for (GroupObject *go = group->gobject.first; go; go = go->next) {
- if (go->ob->pd && go->ob->pd->deflect)
- return 1;
- }
- }
- else {
- for (Base *base = scene->base.first; base; base= base->next) {
- if ( (base->lay & layer) && base->object->pd) {
- if (base->object->pd->deflect)
- return 1;
- }
- }
- }
+ unsigned int numobjects;
+ Object **objects = BKE_collision_objects_create(depsgraph, NULL, collection, &numobjects, eModifierType_Collision);
+ BKE_collision_objects_free(objects);
- return 0;
-}
-
-static int query_external_colliders(Scene *scene, Group *group, Object *me)
-{
- return(are_there_deflectors(scene, group, me->lay));
+ return (numobjects != 0);
}
/* --- dependency information functions*/
/* +++ the aabb "force" section*/
-static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int UNUSED(par_layer), struct Object *vertexowner, float UNUSED(time))
+static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), struct Object *vertexowner, float UNUSED(time))
{
Object *ob;
SoftBody *sb=vertexowner->soft;
@@ -1066,7 +1025,7 @@ static int sb_detect_aabb_collisionCached(float UNUSED(force[3]), unsigned int U
/* +++ the face external section*/
static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float face_v3[3], float *damp,
- float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, float time)
+ float force[3], struct Object *vertexowner, float time)
{
Object *ob;
GHash *hash;
@@ -1167,7 +1126,7 @@ static int sb_detect_face_pointCached(float face_v1[3], float face_v2[3], float
static int sb_detect_face_collisionCached(float face_v1[3], float face_v2[3], float face_v3[3], float *damp,
- float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, float time)
+ float force[3], struct Object *vertexowner, float time)
{
Object *ob;
GHash *hash;
@@ -1304,7 +1263,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow)
zero_v3(feedback);
if (sb_detect_face_collisionCached(
sb->bpoint[bf->v1].pos, sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos,
- &damp, feedback, ob->lay, ob, timenow))
+ &damp, feedback, ob, timenow))
{
madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune);
madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune);
@@ -1322,7 +1281,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow)
zero_v3(feedback);
if (sb_detect_face_pointCached(
sb->bpoint[bf->v1].pos, sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos,
- &damp, feedback, ob->lay, ob, timenow))
+ &damp, feedback, ob, timenow))
{
madd_v3_v3fl(sb->bpoint[bf->v1].force, feedback, tune);
madd_v3_v3fl(sb->bpoint[bf->v2].force, feedback, tune);
@@ -1351,7 +1310,7 @@ static void scan_for_ext_face_forces(Object *ob, float timenow)
/* +++ the spring external section*/
static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], float *damp,
- float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, float time)
+ float force[3], struct Object *vertexowner, float time)
{
Object *ob;
GHash *hash;
@@ -1470,7 +1429,7 @@ static int sb_detect_edge_collisionCached(float edge_v1[3], float edge_v2[3], fl
return deflected;
}
-static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *do_effector)
+static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *effectors)
{
SoftBody *sb = ob->soft;
int a;
@@ -1488,7 +1447,7 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
/* +++ springs colliding */
if (ob->softflag & OB_SB_EDGECOLL) {
if ( sb_detect_edge_collisionCached (sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos,
- &damp, feedback, ob->lay, ob, timenow)) {
+ &damp, feedback, ob, timenow)) {
add_v3_v3(bs->ext_force, feedback);
bs->flag |= BSF_INTERSECT;
//bs->cf=damp;
@@ -1504,14 +1463,14 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
float vel[3], sp[3], pr[3], force[3];
float f, windfactor = 0.25f;
/*see if we have wind*/
- if (do_effector) {
+ if (effectors) {
EffectedPoint epoint;
float speed[3] = {0.0f, 0.0f, 0.0f};
float pos[3];
mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos, sb->bpoint[bs->v2].pos);
mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec, sb->bpoint[bs->v2].vec);
pd_point_from_soft(scene, pos, vel, -1, &epoint);
- pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
mul_v3_fl(speed, windfactor);
add_v3_v3(vel, speed);
@@ -1544,32 +1503,30 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
}
-static void scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow)
+static void scan_for_ext_spring_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float timenow)
{
SoftBody *sb = ob->soft;
- ListBase *do_effector = NULL;
- do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
- _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector);
- pdEndEffectors(&do_effector);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights);
+ _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, effectors);
+ BKE_effectors_free(effectors);
}
static void *exec_scan_for_ext_spring_forces(void *data)
{
SB_thread_context *pctx = (SB_thread_context*)data;
- _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->do_effector);
+ _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->effectors);
return NULL;
}
-static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void)))
+static void sb_sfesf_threads_run(struct Depsgraph *depsgraph, Scene *scene, struct Object *ob, float timenow, int totsprings, int *UNUSED(ptr_to_break_func(void)))
{
- ListBase *do_effector = NULL;
ListBase threads;
SB_thread_context *sb_threads;
int i, totthread, left, dec;
int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
- do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, ob->soft->effector_weights);
/* figure the number of threads while preventing pretty pointless threading overhead */
totthread= BKE_scene_num_threads(scene);
@@ -1594,7 +1551,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,
}
else
sb_threads[i].ifirst = 0;
- sb_threads[i].do_effector = do_effector;
+ sb_threads[i].effectors = effectors;
sb_threads[i].do_deflector = false;// not used here
sb_threads[i].fieldfactor = 0.0f;// not used here
sb_threads[i].windfactor = 0.0f;// not used here
@@ -1614,7 +1571,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,
/* clean up */
MEM_freeN(sb_threads);
- pdEndEffectors(&do_effector);
+ BKE_effectors_free(effectors);
}
@@ -1649,7 +1606,7 @@ static int choose_winner(float*w, float* pos, float*a, float*b, float*c, float*c
static int sb_detect_vertex_collisionCached(
float opco[3], float facenormal[3], float *damp,
- float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner,
+ float force[3], struct Object *vertexowner,
float time, float vel[3], float *intrusion)
{
Object *ob= NULL;
@@ -1845,8 +1802,8 @@ static int sb_deflect_face(Object *ob, float *actpos, float *facenormal, float *
float s_actpos[3];
int deflected;
copy_v3_v3(s_actpos, actpos);
- deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force, ob->lay, ob, time, vel, intrusion);
- //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force, ob->lay, ob, time, vel, intrusion);
+ deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force, ob, time, vel, intrusion);
+ //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force, ob, time, vel, intrusion);
return(deflected);
}
@@ -1969,7 +1926,7 @@ static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, floa
/* since this is definitely the most CPU consuming task here .. try to spread it */
/* core function _softbody_calc_forces_slice_in_a_thread */
/* result is int to be able to flag user break */
-static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor)
+static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow, int ifirst, int ilast, int *UNUSED(ptr_to_break_func(void)), ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
{
float iks;
int bb, do_selfcollision, do_springcollision, do_aero;
@@ -2088,14 +2045,14 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
}
/* particle field & vortex */
- if (do_effector) {
+ if (effectors) {
EffectedPoint epoint;
float kd;
float force[3] = {0.0f, 0.0f, 0.0f};
float speed[3] = {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
- pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale);
@@ -2170,11 +2127,11 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
static void *exec_softbody_calc_forces(void *data)
{
SB_thread_context *pctx = (SB_thread_context*)data;
- _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->do_effector, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor);
+ _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->effectors, pctx->do_deflector, pctx->fieldfactor, pctx->windfactor);
return NULL;
}
-static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *do_effector, int do_deflector, float fieldfactor, float windfactor)
+static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow, int totpoint, int *UNUSED(ptr_to_break_func(void)), struct ListBase *effectors, int do_deflector, float fieldfactor, float windfactor)
{
ListBase threads;
SB_thread_context *sb_threads;
@@ -2206,7 +2163,7 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
}
else
sb_threads[i].ifirst = 0;
- sb_threads[i].do_effector = do_effector;
+ sb_threads[i].effectors = effectors;
sb_threads[i].do_deflector = do_deflector;
sb_threads[i].fieldfactor = fieldfactor;
sb_threads[i].windfactor = windfactor;
@@ -2229,14 +2186,13 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
MEM_freeN(sb_threads);
}
-static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow)
+static void softbody_calc_forcesEx(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow)
{
/* rule we never alter free variables :bp->vec bp->pos in here !
* this will ruin adaptive stepsize AKA heun! (BM)
*/
SoftBody *sb= ob->soft; /* is supposed to be there */
/*BodyPoint *bproot;*/ /* UNUSED */
- ListBase *do_effector = NULL;
/* float gravity; */ /* UNUSED */
/* float iks; */
float fieldfactor = -1.0f, windfactor = 0.25;
@@ -2245,7 +2201,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
/* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */
/* check conditions for various options */
- do_deflector= query_external_colliders(scene, sb->collision_group, ob);
+ do_deflector= query_external_colliders(depsgraph, sb->collision_group);
/* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */
do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
@@ -2254,31 +2210,31 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
/* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */
if (do_springcollision || do_aero)
- sb_sfesf_threads_run(scene, ob, timenow, sb->totspring, NULL);
+ sb_sfesf_threads_run(depsgraph, scene, ob, timenow, sb->totspring, NULL);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, sb->effector_weights);
if (do_deflector) {
float defforce[3];
- do_deflector = sb_detect_aabb_collisionCached(defforce, ob->lay, ob, timenow);
+ do_deflector = sb_detect_aabb_collisionCached(defforce, ob, timenow);
}
- sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, do_effector, do_deflector, fieldfactor, windfactor);
+ sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, effectors, do_deflector, fieldfactor, windfactor);
/* finally add forces caused by face collision */
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
/* finish matrix and solve */
- pdEndEffectors(&do_effector);
+ BKE_effectors_free(effectors);
}
-static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow)
+static void softbody_calc_forces(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float forcetime, float timenow)
{
/* redirection to the new threaded Version */
if (!(G.debug_value & 0x10)) { // 16
- softbody_calc_forcesEx(scene, ob, forcetime, timenow);
+ softbody_calc_forcesEx(depsgraph, scene, ob, forcetime, timenow);
return;
}
else {
@@ -2297,7 +2253,6 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
BodyPoint *bp;
/* BodyPoint *bproot; */ /* UNUSED */
BodySpring *bs;
- ListBase *do_effector = NULL;
float iks, ks, kd, gravity[3] = {0.0f, 0.0f, 0.0f};
float fieldfactor = -1.0f, windfactor = 0.25f;
float tune = sb->ballstiff;
@@ -2309,7 +2264,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
}
/* check conditions for various options */
- do_deflector= query_external_colliders(scene, sb->collision_group, ob);
+ do_deflector= query_external_colliders(depsgraph, sb->collision_group);
do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF));
do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
@@ -2317,13 +2272,13 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */
/* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */
- if (do_springcollision || do_aero) scan_for_ext_spring_forces(scene, ob, timenow);
+ if (do_springcollision || do_aero) scan_for_ext_spring_forces(depsgraph, scene, ob, timenow);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights, true);
+ ListBase *effectors = BKE_effectors_create(depsgraph, ob, NULL, ob->soft->effector_weights);
if (do_deflector) {
float defforce[3];
- do_deflector = sb_detect_aabb_collisionCached(defforce, ob->lay, ob, timenow);
+ do_deflector = sb_detect_aabb_collisionCached(defforce, ob, timenow);
}
bp = sb->bpoint;
@@ -2422,13 +2377,13 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* particle field & vortex */
- if (do_effector) {
+ if (effectors) {
EffectedPoint epoint;
float force[3] = {0.0f, 0.0f, 0.0f};
float speed[3] = {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
- pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+ BKE_effectors_apply(effectors, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
mul_v3_fl(force, fieldfactor* eval_sb_fric_force_scale);
@@ -2520,7 +2475,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* finally add forces caused by face collision */
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob, timenow);
- pdEndEffectors(&do_effector);
+ BKE_effectors_free(effectors);
}
}
@@ -3321,7 +3276,8 @@ SoftBody *sbNew(Scene *scene)
sb->shearstiff = 1.0f;
sb->solverflags |= SBSO_OLDERR;
- sb->pointcache = BKE_ptcache_add(&sb->ptcaches);
+ sb->shared = MEM_callocN(sizeof(*sb->shared), "SoftBody_Shared");
+ sb->shared->pointcache = BKE_ptcache_add(&sb->shared->ptcaches);
if (!sb->effector_weights)
sb->effector_weights = BKE_add_effector_weights(NULL);
@@ -3332,14 +3288,26 @@ SoftBody *sbNew(Scene *scene)
}
/* frees all */
-void sbFree(SoftBody *sb)
+void sbFree(Object *ob)
{
+ SoftBody *sb = ob->soft;
+ if (sb == NULL) {
+ return;
+ }
+
free_softbody_intern(sb);
- BKE_ptcache_free_list(&sb->ptcaches);
- sb->pointcache = NULL;
+
+ if ((ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0) {
+ /* Only free shared data on non-CoW copies */
+ BKE_ptcache_free_list(&sb->shared->ptcaches);
+ sb->shared->pointcache = NULL;
+ MEM_freeN(sb->shared);
+ }
if (sb->effector_weights)
MEM_freeN(sb->effector_weights);
MEM_freeN(sb);
+
+ ob->soft = NULL;
}
void sbFreeSimulation(SoftBody *sb)
@@ -3506,7 +3474,7 @@ static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int
}
}
-static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
+static void softbody_step(struct Depsgraph *depsgraph, Scene *scene, Object *ob, SoftBody *sb, float dtime)
{
/* the simulator */
float forcetime;
@@ -3520,12 +3488,10 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
*/
if (dtime < 0 || dtime > 10.5f) return;
- ccd_update_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
+ ccd_update_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
if (sb->scratch->needstobuildcollider) {
- if (query_external_colliders(scene, sb->collision_group, ob)) {
- ccd_build_deflector_hash(scene, sb->collision_group, ob, sb->scratch->colliderhash);
- }
+ ccd_build_deflector_hash(depsgraph, sb->collision_group, ob, sb->scratch->colliderhash);
sb->scratch->needstobuildcollider=0;
}
@@ -3554,12 +3520,12 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
sb->scratch->flag &= ~SBF_DOFUZZY;
/* do predictive euler step */
- softbody_calc_forces(scene, ob, forcetime, timedone/dtime);
+ softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime);
softbody_apply_forces(ob, forcetime, 1, NULL, mid_flags);
/* crop new slope values to do averaged slope step */
- softbody_calc_forces(scene, ob, forcetime, timedone/dtime);
+ softbody_calc_forces(depsgraph, scene, ob, forcetime, timedone/dtime);
softbody_apply_forces(ob, forcetime, 2, &err, mid_flags);
softbody_apply_goalsnap(ob);
@@ -3640,7 +3606,7 @@ static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime)
}
/* simulates one step. framenr is in frames */
-void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
+void sbObjectStep(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts)
{
SoftBody *sb= ob->soft;
PointCache *cache;
@@ -3648,8 +3614,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
float dtime, timescale;
int framedelta, framenr, startframe, endframe;
int cache_result;
-
- cache= sb->pointcache;
+ cache= sb->shared->pointcache;
framenr= (int)cfra;
framedelta= framenr - cache->simframe;
@@ -3717,7 +3682,8 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
}
/* try to read from cache */
- bool can_simulate = (framenr == sb->last_frame+1) && !(cache->flag & PTCACHE_BAKED);
+ bool can_write_cache = DEG_is_active(depsgraph);
+ bool can_simulate = (framenr == sb->last_frame + 1) && !(cache->flag & PTCACHE_BAKED) && can_write_cache;
cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe, can_simulate);
@@ -3728,7 +3694,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
BKE_ptcache_validate(cache, framenr);
- if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED)
+ if (cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED && can_write_cache)
BKE_ptcache_write(&pid, framenr);
sb->last_frame = framenr;
@@ -3740,7 +3706,9 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
}
else if (/*ob->id.lib || */(cache->flag & PTCACHE_BAKED)) { /* "library linking & pointcaches" has to be solved properly at some point */
/* if baked and nothing in cache, do nothing */
- BKE_ptcache_invalidate(cache);
+ if (can_write_cache) {
+ BKE_ptcache_invalidate(cache);
+ }
return;
}
@@ -3757,7 +3725,7 @@ void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], i
dtime = framedelta*timescale;
/* do simulation */
- softbody_step(scene, ob, sb, dtime);
+ softbody_step(depsgraph, scene, ob, sb, dtime);
softbody_to_object(ob, vertexCos, numVerts, 0);
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index d21055ada6a..5135362bd69 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -48,13 +48,11 @@
#include "DNA_speaker_types.h"
#ifdef WITH_AUDASPACE
-# include AUD_SOUND_H
-# include AUD_SEQUENCE_H
-# include AUD_HANDLE_H
-# include AUD_SPECIAL_H
-# ifdef WITH_SYSTEM_AUDASPACE
-# include "../../../intern/audaspace/intern/AUD_Set.h"
-# endif
+# include <AUD_Sound.h>
+# include <AUD_Sequence.h>
+# include <AUD_Handle.h>
+# include <AUD_Special.h>
+# include "../../../intern/audaspace/intern/AUD_Set.h"
#endif
#include "BKE_global.h"
@@ -228,7 +226,7 @@ void BKE_sound_init_once(void)
atexit(BKE_sound_exit_once);
}
-static AUD_Device *sound_device;
+static AUD_Device *sound_device = NULL;
void *BKE_sound_get_device(void)
{
@@ -237,6 +235,9 @@ void *BKE_sound_get_device(void)
void BKE_sound_init(struct Main *bmain)
{
+ /* Make sure no instance of the sound system is running, otherwise we get leaks. */
+ BKE_sound_exit();
+
AUD_DeviceSpecs specs;
int device, buffersize;
const char *device_name;
@@ -302,7 +303,6 @@ void BKE_sound_exit_once(void)
sound_device = NULL;
AUD_exitOnce();
-#ifdef WITH_SYSTEM_AUDASPACE
if (audio_device_names != NULL) {
int i;
for (i = 0; audio_device_names[i]; i++) {
@@ -311,7 +311,6 @@ void BKE_sound_exit_once(void)
free(audio_device_names);
audio_device_names = NULL;
}
-#endif
}
/* XXX unused currently */
@@ -811,13 +810,76 @@ void BKE_sound_read_waveform(bSound *sound, short *stop)
BLI_spin_unlock(sound->spinlock);
}
-void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
+static void sound_update_base(Scene *scene, Base *base, void *new_set)
{
- Object *ob;
- Base *base;
+ Object *ob = base->object;
NlaTrack *track;
NlaStrip *strip;
Speaker *speaker;
+ float quat[4];
+
+ if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
+ return;
+ }
+
+ ob->id.tag &= ~LIB_TAG_DOIT;
+
+ if ((ob->type != OB_SPEAKER) || !ob->adt) {
+ return;
+ }
+
+ for (track = ob->adt->nla_tracks.first; track; track = track->next) {
+ for (strip = track->strips.first; strip; strip = strip->next) {
+ if (strip->type != NLASTRIP_TYPE_SOUND) {
+ continue;
+ }
+ speaker = (Speaker *)ob->data;
+
+ if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
+ if (speaker->sound) {
+ AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
+ }
+ else {
+ AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
+ strip->speaker_handle = NULL;
+ }
+ }
+ else {
+ if (speaker->sound) {
+ strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
+ speaker->sound->playback_handle,
+ (double)strip->start / FPS, FLT_MAX, 0);
+ AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
+ }
+ }
+
+ if (strip->speaker_handle) {
+ const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
+ AUD_addSet(new_set, strip->speaker_handle);
+ AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
+ AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
+ AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
+ AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
+ AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
+ AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
+ AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
+ AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
+
+ mat4_to_quat(quat, ob->obmat);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
+ AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
+ AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
+ AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
+ }
+ }
+ }
+}
+
+void BKE_sound_update_scene(Main *bmain, Scene *scene)
+{
+ Base *base;
Scene *sce_it;
void *new_set = AUD_createSet();
@@ -826,59 +888,18 @@ void BKE_sound_update_scene(Main *bmain, struct Scene *scene)
/* cheap test to skip looping over all objects (no speakers is a common case) */
if (!BLI_listbase_is_empty(&bmain->speaker)) {
- for (SETLOOPER(scene, sce_it, base)) {
- ob = base->object;
- if ((ob->type != OB_SPEAKER) || !ob->adt) {
- continue;
- }
- for (track = ob->adt->nla_tracks.first; track; track = track->next) {
- for (strip = track->strips.first; strip; strip = strip->next) {
- if (strip->type != NLASTRIP_TYPE_SOUND) {
- continue;
- }
- speaker = (Speaker *)ob->data;
-
- if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
- if (speaker->sound) {
- AUD_SequenceEntry_move(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
- }
- else {
- AUD_Sequence_remove(scene->sound_scene, strip->speaker_handle);
- strip->speaker_handle = NULL;
- }
- }
- else {
- if (speaker->sound) {
- strip->speaker_handle = AUD_Sequence_add(scene->sound_scene,
- speaker->sound->playback_handle,
- (double)strip->start / FPS, FLT_MAX, 0);
- AUD_SequenceEntry_setRelative(strip->speaker_handle, 0);
- }
- }
-
- if (strip->speaker_handle) {
- const bool mute = ((strip->flag & NLASTRIP_FLAG_MUTED) || (speaker->flag & SPK_MUTED));
- AUD_addSet(new_set, strip->speaker_handle);
- AUD_SequenceEntry_setVolumeMaximum(strip->speaker_handle, speaker->volume_max);
- AUD_SequenceEntry_setVolumeMinimum(strip->speaker_handle, speaker->volume_min);
- AUD_SequenceEntry_setDistanceMaximum(strip->speaker_handle, speaker->distance_max);
- AUD_SequenceEntry_setDistanceReference(strip->speaker_handle, speaker->distance_reference);
- AUD_SequenceEntry_setAttenuation(strip->speaker_handle, speaker->attenuation);
- AUD_SequenceEntry_setConeAngleOuter(strip->speaker_handle, speaker->cone_angle_outer);
- AUD_SequenceEntry_setConeAngleInner(strip->speaker_handle, speaker->cone_angle_inner);
- AUD_SequenceEntry_setConeVolumeOuter(strip->speaker_handle, speaker->cone_volume_outer);
-
- mat4_to_quat(quat, ob->obmat);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_LOCATION, CFRA, ob->obmat[3], 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
- AUD_SequenceEntry_setAnimationData(strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
- AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
- AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
- }
- }
+ BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, true);
+
+ for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (base = view_layer->object_bases.first; base; base = base->next) {
+ sound_update_base(scene, base, new_set);
}
}
+
+ for (SETLOOPER_SET_ONLY(scene, sce_it, base)) {
+ sound_update_base(scene, base, new_set);
+ }
+
}
while ((handle = AUD_getSet(scene->speaker_handles))) {
@@ -911,28 +932,12 @@ float BKE_sound_get_length(bSound *sound)
char **BKE_sound_get_device_names(void)
{
if (audio_device_names == NULL) {
-#ifdef WITH_SYSTEM_AUDASPACE
audio_device_names = AUD_getDeviceNames();
-#else
- static const char *names[] = {
- "Null", "SDL", "OpenAL", "JACK", NULL
- };
- audio_device_names = (char **)names;
-#endif
}
return audio_device_names;
}
-bool BKE_sound_is_jack_supported(void)
-{
-#ifdef WITH_SYSTEM_AUDASPACE
- return 1;
-#else
- return (bool)AUD_isJackSupported();
-#endif
-}
-
#else /* WITH_AUDASPACE */
#include "BLI_utildefines.h"
@@ -979,5 +984,6 @@ void BKE_sound_set_scene_sound_pan(void *UNUSED(handle), float UNUSED(pan), char
void BKE_sound_set_scene_volume(struct Scene *UNUSED(scene), float UNUSED(volume)) {}
void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle), float UNUSED(pitch), char UNUSED(animated)) {}
float BKE_sound_get_length(struct bSound *UNUSED(sound)) { return 0; }
-bool BKE_sound_is_jack_supported(void) { return false; }
+char **BKE_sound_get_device_names(void) { static char *names[1] = {NULL}; return names; }
+
#endif /* WITH_AUDASPACE */
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
new file mode 100644
index 00000000000..df5cc7551aa
--- /dev/null
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -0,0 +1,1242 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006-2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenkernel/intern/studiolight.c
+ * \ingroup bke
+ */
+
+#include "BKE_studiolight.h"
+
+#include "BKE_appdir.h"
+#include "BKE_icons.h"
+
+#include "BLI_fileops.h"
+#include "BLI_fileops_types.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+#include "BLI_path_util.h"
+#include "BLI_rand.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "DNA_listBase.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "GPU_texture.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* Statics */
+static ListBase studiolights;
+static int last_studiolight_id = 0;
+#define STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE 128
+#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT 32
+#define STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH (STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * 2)
+
+#define STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE 0
+#define STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS 1
+/*
+ * The method to calculate the irradiance buffers
+ * The irradiance buffer is only shown in the background when in LookDev.
+ *
+ * STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE is very slow, but very accurate
+ * STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS is faster but has artifacts
+ */
+// #define STUDIOLIGHT_IRRADIANCE_METHOD STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+#define STUDIOLIGHT_IRRADIANCE_METHOD STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL == 2
+# define STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING
+#endif
+
+/*
+ * Disable this option so caches are not loaded from disk
+ * Do not checkin with this commented out
+ */
+#define STUDIOLIGHT_LOAD_CACHED_FILES
+
+static const char *STUDIOLIGHT_CAMERA_FOLDER = "studiolights/camera/";
+static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/";
+static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/";
+
+/* FUNCTIONS */
+#define IMB_SAFE_FREE(p) do { \
+if (p) { \
+ IMB_freeImBuf(p); \
+ p = NULL; \
+} \
+} while (0)
+
+#define GPU_TEXTURE_SAFE_FREE(p) do { \
+if (p) { \
+ GPU_texture_free(p); \
+ p = NULL; \
+} \
+} while (0)
+
+static void studiolight_free(struct StudioLight *sl)
+{
+#define STUDIOLIGHT_DELETE_ICON(s) { \
+ if (s != 0) { \
+ BKE_icon_delete(s); \
+ s = 0; \
+ } \
+}
+ if (sl->free_function) {
+ sl->free_function(sl, sl->free_function_data);
+ }
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_radiance);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_irradiance);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap);
+ STUDIOLIGHT_DELETE_ICON(sl->icon_id_matcap_flipped);
+#undef STUDIOLIGHT_DELETE_ICON
+
+ for (int index = 0; index < 6; index++) {
+ IMB_SAFE_FREE(sl->radiance_cubemap_buffers[index]);
+ }
+ GPU_TEXTURE_SAFE_FREE(sl->equirectangular_radiance_gputexture);
+ GPU_TEXTURE_SAFE_FREE(sl->equirectangular_irradiance_gputexture);
+ IMB_SAFE_FREE(sl->equirectangular_radiance_buffer);
+ IMB_SAFE_FREE(sl->equirectangular_irradiance_buffer);
+ MEM_SAFE_FREE(sl->path_irr_cache);
+ MEM_SAFE_FREE(sl->path_sh_cache);
+ MEM_SAFE_FREE(sl->gpu_matcap_3components);
+ MEM_SAFE_FREE(sl);
+}
+
+static struct StudioLight *studiolight_create(int flag)
+{
+ struct StudioLight *sl = MEM_callocN(sizeof(*sl), __func__);
+ sl->path[0] = 0x00;
+ sl->name[0] = 0x00;
+ sl->path_irr_cache = NULL;
+ sl->path_sh_cache = NULL;
+ sl->free_function = NULL;
+ sl->flag = flag;
+ sl->index = ++last_studiolight_id;
+ if (flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) {
+ sl->icon_id_matcap = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP);
+ sl->icon_id_matcap_flipped = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED);
+ }
+ else {
+ sl->icon_id_radiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_RADIANCE);
+ sl->icon_id_irradiance = BKE_icon_ensure_studio_light(sl, STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE);
+ }
+
+ for (int index = 0; index < 6; index++) {
+ sl->radiance_cubemap_buffers[index] = NULL;
+ }
+
+ return sl;
+}
+
+static void direction_to_equirectangular(float r[2], const float dir[3])
+{
+ r[0] = (atan2f(dir[1], dir[0]) - M_PI) / -(M_PI * 2);
+ r[1] = (acosf(dir[2] / 1.0) - M_PI) / -M_PI;
+}
+
+static void equirectangular_to_direction(float r[3], float u, float v)
+{
+ float phi = (-(M_PI * 2)) * u + M_PI;
+ float theta = -M_PI * v + M_PI;
+ float sin_theta = sinf(theta);
+ r[0] = sin_theta * cosf(phi);
+ r[1] = sin_theta * sinf(phi);
+ r[2] = cosf(theta);
+}
+
+static void studiolight_calculate_radiance(ImBuf *ibuf, float color[4], const float direction[3])
+{
+ float uv[2];
+ direction_to_equirectangular(uv, direction);
+ nearest_interpolation_color_wrap(ibuf, NULL, color, uv[0] * ibuf->x, uv[1] * ibuf->y);
+}
+
+static void studiolight_calculate_radiance_buffer(
+ ImBuf *ibuf, float *colbuf,
+ const float start_x, const float add_x,
+ const float start_y, const float add_y, const float z,
+ const int index_x, const int index_y, const int index_z)
+{
+ float direction[3];
+ float yf = start_y;
+ float xf;
+ float *color = colbuf;
+
+ for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++, yf += add_y) {
+ xf = start_x;
+ for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++, xf += add_x) {
+ direction[index_x] = xf;
+ direction[index_y] = yf;
+ direction[index_z] = z;
+ normalize_v3(direction);
+ studiolight_calculate_radiance(ibuf, color, direction);
+ color += 4;
+ }
+ }
+}
+
+static void studiolight_load_equirectangular_image(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ ImBuf *ibuf = NULL;
+ ibuf = IMB_loadiffname(sl->path, 0, NULL);
+ if (ibuf == NULL) {
+ float *colbuf = MEM_mallocN(sizeof(float[4]), __func__);
+ copy_v4_fl4(colbuf, 1.0f, 0.0f, 1.0f, 1.0f);
+ ibuf = IMB_allocFromBuffer(NULL, colbuf, 1, 1);
+ }
+ IMB_float_from_rect(ibuf);
+ sl->equirectangular_radiance_buffer = ibuf;
+ }
+ sl->flag |= STUDIOLIGHT_EXTERNAL_IMAGE_LOADED;
+}
+
+static void studiolight_create_equirectangular_radiance_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ char error[256];
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ ImBuf *ibuf = sl->equirectangular_radiance_buffer;
+
+ if (sl->flag & STUDIOLIGHT_ORIENTATION_VIEWNORMAL) {
+ sl->gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__);
+
+ float *offset4 = ibuf->rect_float;
+ float *offset3 = sl->gpu_matcap_3components;
+ for (int i = 0; i < ibuf->x * ibuf->y; i++) {
+ copy_v3_v3(offset3, offset4);
+ offset3 += 3;
+ offset4 += 4;
+ }
+ sl->equirectangular_radiance_gputexture = GPU_texture_create_nD(
+ ibuf->x, ibuf->y, 0, 2, sl->gpu_matcap_3components, GPU_R11F_G11F_B10F, GPU_DATA_FLOAT, 0, false, error);
+ }
+ else {
+ sl->equirectangular_radiance_gputexture = GPU_texture_create_2D(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ GPUTexture *tex = sl->equirectangular_radiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE;
+}
+
+static void studiolight_create_equirectangular_irradiance_gputexture(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ char error[256];
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
+ ImBuf *ibuf = sl->equirectangular_irradiance_buffer;
+ sl->equirectangular_irradiance_gputexture = GPU_texture_create_2D(
+ ibuf->x, ibuf->y, GPU_RGBA16F, ibuf->rect_float, error);
+ GPUTexture *tex = sl->equirectangular_irradiance_gputexture;
+ GPU_texture_bind(tex, 0);
+ GPU_texture_filter_mode(tex, true);
+ GPU_texture_wrap_mode(tex, true);
+ GPU_texture_unbind(tex);
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE;
+}
+
+static void studiolight_calculate_radiance_cubemap_buffers(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+ ImBuf *ibuf = sl->equirectangular_radiance_buffer;
+ if (ibuf) {
+ float *colbuf = MEM_mallocN(SQUARE(STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * sizeof(float[4]), __func__);
+ const float add = 1.0f / (STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE + 1);
+ const float start = ((1.0f / STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) * 0.5f) - 0.5f;
+
+ /* front */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, 0.5f, 0, 2, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* back */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, -0.5f, 0, 2, 1);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* left */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, -start, -add, start, add, 0.5f, 1, 2, 0);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* right */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 1, 2, 0);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* top */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, start, add, -0.5f, 0, 1, 2);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+ /* bottom */
+ studiolight_calculate_radiance_buffer(ibuf, colbuf, start, add, -start, -add, 0.5f, 0, 1, 2);
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS] = IMB_allocFromBuffer(
+ NULL, colbuf, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+
+#if 0
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], "/tmp/studiolight_radiance_left.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], "/tmp/studiolight_radiance_right.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], "/tmp/studiolight_radiance_front.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], "/tmp/studiolight_radiance_back.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], "/tmp/studiolight_radiance_bottom.png", IB_rectfloat);
+ IMB_saveiff(sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], "/tmp/studiolight_radiance_top.png", IB_rectfloat);
+#endif
+ MEM_freeN(colbuf);
+ }
+ }
+ sl->flag |= STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED;
+}
+
+BLI_INLINE void studiolight_evaluate_radiance_buffer(
+ ImBuf *radiance_buffer, const float normal[3], float color[3], int *hits,
+ int xoffset, int yoffset, int zoffset, float zvalue)
+{
+ if (radiance_buffer == NULL) {
+ return;
+ }
+ float angle;
+ float *radiance_color = radiance_buffer->rect_float;
+ float direction[3];
+ for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++) {
+ for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++) {
+ // calculate light direction;
+ direction[zoffset] = zvalue;
+ direction[xoffset] = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
+ direction[yoffset] = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
+ normalize_v3(direction);
+ angle = fmax(0.0f, dot_v3v3(direction, normal));
+ madd_v3_v3fl(color, radiance_color, angle);
+ (*hits)++;
+ radiance_color += 4;
+ }
+ }
+
+}
+
+/*
+ * Spherical Harmonics
+ */
+BLI_INLINE float studiolight_area_element(float x, float y)
+{
+ return atan2(x * y, sqrtf(x * x + y * y + 1));
+}
+
+BLI_INLINE float studiolight_texel_solid_angle(float x, float y, float halfpix)
+{
+ float v1x = (x - halfpix) * 2.0f - 1.0f;
+ float v1y = (y - halfpix) * 2.0f - 1.0f;
+ float v2x = (x + halfpix) * 2.0f - 1.0f;
+ float v2y = (y + halfpix) * 2.0f - 1.0f;
+
+ return studiolight_area_element(v1x, v1y) - studiolight_area_element(v1x, v2y) - studiolight_area_element(v2x, v1y) + studiolight_area_element(v2x, v2y);
+}
+
+static void studiolight_calculate_cubemap_vector_weight(float normal[3], float *weight, int face, float x, float y)
+{
+ copy_v3_fl3(normal, x * 2.0f - 1.0f, y * 2.0f - 1.0f, 1.0f);
+ const float conversion_matrices[6][3][3] = {
+ {
+ {0.0f, 0.0f, 1.0f},
+ {0.0f, -1.0f, 0.0f},
+ {1.0f, 0.0f, 0.0f},
+ },
+ {
+ {0.0f, 0.0f, -1.0f},
+ {0.0f, -1.0f, 0.0f},
+ {-1.0f, 0.0f, 0.0f},
+ },
+ {
+ {1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, -1.0f},
+ {0.0f, 1.0f, 0.0f},
+ },
+ {
+ {1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 1.0f},
+ {0.0f, -1.0f, 0.0f},
+ },
+ {
+ {1.0f, 0.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f},
+ {0.0f, 0.0f, -1.0f},
+ },
+ {
+ {-1.0f, 0.0f, 0.0f},
+ {0.0f, -1.0f, 0.0f},
+ {0.0f, 0.0f, 1.0f},
+ }
+ };
+
+ mul_m3_v3(conversion_matrices[face], normal);
+ normalize_v3(normal);
+ const float halfpix = 1.0f / (2.0f * STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ *weight = studiolight_texel_solid_angle(x + halfpix, y + halfpix, halfpix);
+}
+
+static void studiolight_calculate_spherical_harmonics_coefficient(StudioLight *sl, int sh_component)
+{
+ const float M_4PI = M_PI * 4.0f;
+
+ float weight_accum = 0.0f;
+ float sh[3] = {0.0f, 0.0f, 0.0f};
+ for (int face = 0; face < 6; face++) {
+ float *color;
+ color = sl->radiance_cubemap_buffers[face]->rect_float;
+ for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++) {
+ float yf = y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE;
+ for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++) {
+ float xf = x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE;
+ float weight, coef;
+ float cubevec[3];
+ studiolight_calculate_cubemap_vector_weight(cubevec, &weight, face, xf, yf);
+
+ const float nx = cubevec[0];
+ const float ny = cubevec[1];
+ const float nz = cubevec[2];
+ const float nx2 = SQUARE(nx);
+ const float ny2 = SQUARE(ny);
+ const float nz2 = SQUARE(nz);
+ const float nx4 = SQUARE(nx2);
+ const float ny4 = SQUARE(ny2);
+ const float nz4 = SQUARE(nz2);
+
+ switch (sh_component) {
+ /* L0 */
+ case 0:
+ coef = 0.2822095f;
+ break;
+ /* L1 */
+ case 1:
+ coef = -0.488603f * nz * 2.0f / 3.0f;
+ break;
+ case 2:
+ coef = 0.488603f * ny * 2.0f / 3.0f;
+ break;
+ case 3:
+ coef = -0.488603f * nx * 2.0f / 3.0f;
+ break;
+ /* L2 */
+ case 4:
+ coef = 1.092548f * nx * nz * 1.0f / 4.0f;
+ break;
+ case 5:
+ coef = -1.092548f * nz * ny * 1.0f / 4.0f;
+ break;
+ case 6:
+ coef = 0.315392f * (3.0f * ny2 - 1.0f) * 1.0f / 4.0f;
+ break;
+ case 7:
+ coef = 1.092548f * nx * ny * 1.0f / 4.0f;
+ break;
+ case 8:
+ coef = 0.546274f * (nx2 - nz2) * 1.0f / 4.0f;
+ break;
+ /* L4 */
+ case 9:
+ coef = (2.5033429417967046f * nx * nz * (nx2 - nz2)) / -24.0f;
+ break;
+ case 10:
+ coef = (-1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2)) / -24.0f;
+ break;
+ case 11:
+ coef = (0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2)) / -24.0f;
+ break;
+ case 12:
+ coef = (-0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2)) / -24.0f;
+ break;
+ case 13:
+ coef = ((105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f) / -24.0f;
+ break;
+ case 14:
+ coef = (-0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2)) / -24.0f;
+ break;
+ case 15:
+ coef = (0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2)) / -24.0f;
+ break;
+ case 16:
+ coef = (-1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2)) / -24.0f;
+ break;
+ case 17:
+ coef = (0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4)) / -24.0f;
+ break;
+ default:
+ coef = 0.0f;
+ }
+
+ madd_v3_v3fl(sh, color, coef * weight);
+ weight_accum += weight;
+ color += 4;
+ }
+ }
+ }
+
+ mul_v3_fl(sh, M_4PI / weight_accum);
+ copy_v3_v3(sl->spherical_harmonics_coefs[sh_component], sh);
+}
+
+#ifdef STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING
+static void studiolight_calculate_spherical_harmonics_luminance(StudioLight *sl, float luminance[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS])
+{
+ for (int index = 0; index < STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS; index++) {
+ luminance[index] = rgb_to_grayscale(sl->spherical_harmonics_coefs[index]);
+ }
+}
+
+static void studiolight_apply_spherical_harmonics_windowing(StudioLight *sl, float max_lamplacian)
+{
+ /* From Peter-Pike Sloan's Stupid SH Tricks http://www.ppsloan.org/publications/StupidSH36.pdf */
+ float table_l[STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL + 1];
+ float table_b[STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL + 1];
+
+ table_l[0] = 0.0f;
+ table_b[0] = 0.0f;
+
+ /* convert to luminance */
+ float luminance[STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS];
+ studiolight_calculate_spherical_harmonics_luminance(sl, luminance);
+
+ int index = 1;
+ for (int level = 1; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; level++) {
+ table_l[level] = (float)(SQUARE(level) * SQUARE(level + 1));
+
+ float b = 0.0f;
+ for (int m = -1; m <= level; m++) {
+ b += SQUARE(luminance[index++]);
+ }
+ table_b[level] = b;
+ }
+
+ float squared_lamplacian = 0.0f;
+ for (int level = 1; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; level++) {
+ squared_lamplacian += table_l[level] * table_b[level];
+ }
+
+ const float target_squared_laplacian = max_lamplacian * max_lamplacian;
+ if (squared_lamplacian <= target_squared_laplacian) {
+ return;
+ }
+
+ float lambda = 0.0f;
+
+ const int no_iterations = 10000000;
+ for (int i = 0; i < no_iterations; ++i) {
+ float f = 0.0f;
+ float fd = 0.0f;
+
+ for (int level = 1; level <= (int)STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; ++level) {
+ f += table_l[level] * table_b[level] / SQUARE(1.0f + lambda * table_l[level]);
+ fd += (2.0f * SQUARE(table_l[level]) * table_b[level]) / CUBE(1.0f + lambda * table_l[level]);
+ }
+
+ f = target_squared_laplacian - f;
+
+ float delta = -f / fd;
+ lambda += delta;
+
+ if (ABS(delta) < 1e-6f) {
+ break;
+ }
+ }
+
+ /* Apply windowing lambda */
+ index = 0;
+ for (int level = 0; level <= STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL; level++) {
+ float s = 1.0f / (1.0f + lambda * SQUARE(level) * SQUARE(level + 1.0f));
+
+ for (int m = -1; m <= level; m++) {
+ mul_v3_fl(sl->spherical_harmonics_coefs[index++], s);
+ }
+ }
+}
+#endif
+
+BLI_INLINE void studiolight_sample_spherical_harmonics(StudioLight *sl, float color[3], float normal[3])
+{
+ const float nx = normal[0];
+ const float ny = normal[1];
+ const float nz = normal[2];
+
+ copy_v3_fl(color, 0.0f);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[0], 0.282095f);
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 0
+ /* Spherical Harmonics L1 */
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[1], -0.488603f * nz);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[2], 0.488603f * ny);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[3], -0.488603f * nx);
+#endif
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 1
+ /* Spherical Harmonics L2 */
+ const float nx2 = SQUARE(nx);
+ const float ny2 = SQUARE(ny);
+ const float nz2 = SQUARE(nz);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[4], 1.092548f * nx * nz);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[5], -1.092548f * nz * ny);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[6], 0.315392f * (3.0f * ny2 - 1.0f));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[7], -1.092548 * nx * ny);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[8], 0.546274 * (nx2 - nz2));
+#endif
+
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 3
+ /* Spherical Harmonics L4 */
+ const float nx4 = SQUARE(nx2);
+ const float ny4 = SQUARE(ny2);
+ const float nz4 = SQUARE(nz2);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[9], 2.5033429417967046f * nx * nz * (nx2 - nz2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[10], -1.7701307697799304f * nz * ny * (3.0f * nx2 - nz2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[11], 0.9461746957575601f * nz * nx * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[12], -0.6690465435572892f * nz * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[13], (105.0f * ny4 - 90.0f * ny2 + 9.0f) / 28.359261614f);
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[14], -0.6690465435572892f * nx * ny * (-3.0f + 7.0f * ny2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[15], 0.9461746957575601f * (nx2 - nz2) * (-1.0f + 7.0f * ny2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[16], -1.7701307697799304f * nx * ny * (nx2 - 3.0f * nz2));
+ madd_v3_v3fl(color, sl->spherical_harmonics_coefs[17], 0.6258357354491761f * (nx4 - 6.0f * nz2 * nx2 + nz4));
+#endif
+
+}
+
+static void studiolight_calculate_diffuse_light(StudioLight *sl)
+{
+ /* init light to black */
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
+
+ for (int comp = 0; comp < STUDIOLIGHT_SPHERICAL_HARMONICS_COMPONENTS; comp++) {
+ studiolight_calculate_spherical_harmonics_coefficient(sl, comp);
+ }
+
+#ifdef STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING
+ studiolight_apply_spherical_harmonics_windowing(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_WINDOWING_TARGET_LAMPLACIAN);
+#endif
+
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ FILE *fp = BLI_fopen(sl->path_sh_cache, "wb");
+ if (fp) {
+ fwrite(sl->spherical_harmonics_coefs, sizeof(sl->spherical_harmonics_coefs), 1, fp);
+ fclose(fp);
+ }
+ }
+ }
+ sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
+}
+
+static float texel_coord_solid_angle(float a_U, float a_V, int a_Size)
+{
+ //scale up to [-1, 1] range (inclusive), offset by 0.5 to point to texel center.
+ float u = (2.0f * ((float)a_U + 0.5f) / (float)a_Size) - 1.0f;
+ float v = (2.0f * ((float)a_V + 0.5f) / (float)a_Size) - 1.0f;
+
+ float resolution_inv = 1.0f / a_Size;
+
+ // U and V are the -1..1 texture coordinate on the current face.
+ // Get projected area for this texel
+ float x0 = u - resolution_inv;
+ float y0 = v - resolution_inv;
+ float x1 = u + resolution_inv;
+ float y1 = v + resolution_inv;
+ return studiolight_area_element(x0, y0) - studiolight_area_element(x0, y1) - studiolight_area_element(x1, y0) + studiolight_area_element(x1, y1);
+}
+
+BLI_INLINE void studiolight_evaluate_specular_radiance_buffer(
+ ImBuf *radiance_buffer, const float normal[3], float color[3],
+ int xoffset, int yoffset, int zoffset, float zvalue)
+{
+ if (radiance_buffer == NULL) {
+ return;
+ }
+ float angle;
+ float *radiance_color = radiance_buffer->rect_float;
+ float direction[3];
+ for (int y = 0; y < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; y++) {
+ for (int x = 0; x < STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE; x++) {
+ // calculate light direction;
+ float u = (x / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
+ float v = (y / (float)STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE) - 0.5f;
+ direction[zoffset] = zvalue;
+ direction[xoffset] = u;
+ direction[yoffset] = v;
+ normalize_v3(direction);
+ angle = fmax(0.0f, dot_v3v3(direction, normal)) * texel_coord_solid_angle(x, y, STUDIOLIGHT_RADIANCE_CUBEMAP_SIZE);
+ madd_v3_v3fl(color, radiance_color, angle);
+ radiance_color += 4;
+ }
+ }
+
+}
+
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+static void studiolight_calculate_specular_irradiance(StudioLight *sl, float color[3], const float normal[3])
+{
+ copy_v3_fl(color, 0.0f);
+
+ /* back */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_POS], normal, color, 0, 2, 1, 0.5);
+ /* front */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Y_NEG], normal, color, 0, 2, 1, -0.5);
+
+ /* left */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_POS], normal, color, 1, 2, 0, 0.5);
+ /* right */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_X_NEG], normal, color, 1, 2, 0, -0.5);
+
+ /* top */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_POS], normal, color, 0, 1, 2, 0.5);
+ /* bottom */
+ studiolight_evaluate_specular_radiance_buffer(
+ sl->radiance_cubemap_buffers[STUDIOLIGHT_Z_NEG], normal, color, 0, 1, 2, -0.5);
+
+ mul_v3_fl(color, 1.0 / M_PI);
+}
+#endif
+
+static bool studiolight_load_irradiance_equirectangular_image(StudioLight *sl)
+{
+#ifdef STUDIOLIGHT_LOAD_CACHED_FILES
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ ImBuf *ibuf = NULL;
+ ibuf = IMB_loadiffname(sl->path_irr_cache, 0, NULL);
+ if (ibuf) {
+ IMB_float_from_rect(ibuf);
+ sl->equirectangular_irradiance_buffer = ibuf;
+ sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED;
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+static bool studiolight_load_spherical_harmonics_coefficients(StudioLight *sl)
+{
+#ifdef STUDIOLIGHT_LOAD_CACHED_FILES
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ FILE *fp = BLI_fopen(sl->path_sh_cache, "rb");
+ if (fp) {
+ if (fread((void *)(sl->spherical_harmonics_coefs), sizeof(sl->spherical_harmonics_coefs), 1, fp)) {
+ sl->flag |= STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED;
+ fclose(fp);
+ return true;
+ }
+ fclose(fp);
+ }
+ }
+#endif
+ return false;
+}
+
+static void studiolight_calculate_irradiance_equirectangular_image(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED);
+#endif
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED);
+#endif
+
+ float *colbuf = MEM_mallocN(STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH * STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT * sizeof(float[4]), __func__);
+ float *color = colbuf;
+ for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT; y++) {
+ float yf = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT;
+
+ for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH; x++) {
+ float xf = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH;
+ float dir[3];
+ equirectangular_to_direction(dir, xf, yf);
+
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ studiolight_calculate_specular_irradiance(sl, color, dir);
+#endif
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_SPHERICAL_HARMONICS
+ studiolight_sample_spherical_harmonics(sl, color, dir);
+#endif
+
+ color[3] = 1.0f;
+ color += 4;
+ }
+ }
+
+ sl->equirectangular_irradiance_buffer = IMB_allocFromBuffer(
+ NULL, colbuf,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH,
+ STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT);
+ MEM_freeN(colbuf);
+
+#if STUDIOLIGHT_IRRADIANCE_METHOD == STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ /*
+ * Only store cached files when using STUDIOLIGHT_IRRADIANCE_METHOD_RADIANCE
+ */
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ IMB_saveiff(sl->equirectangular_irradiance_buffer, sl->path_irr_cache, IB_rectfloat);
+ }
+#endif
+ }
+ sl->flag |= STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED;
+}
+
+static void studiolight_calculate_light_direction(StudioLight *sl)
+{
+ float best_light = 0.0;
+ sl->light_direction[0] = 0.0f;
+ sl->light_direction[1] = 0.0f;
+ sl->light_direction[2] = -1.0f;
+
+ if ((sl->flag & STUDIOLIGHT_EXTERNAL_FILE) && (sl->flag & STUDIOLIGHT_ORIENTATION_WORLD)) {
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED);
+ ImBuf *ibuf = sl->equirectangular_irradiance_buffer;
+ if (ibuf) {
+ /* go over every pixel, determine light, if higher calc direction off the light */
+ float new_light;
+ float *color = ibuf->rect_float;
+ for (int y = 0; y < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT; y++) {
+ for (int x = 0; x < STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH; x++) {
+ new_light = color[0] + color[1] + color[2];
+ if (new_light > best_light) {
+ float u = x / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_WIDTH;
+ float v = y / (float)STUDIOLIGHT_IRRADIANCE_EQUIRECTANGULAR_HEIGHT;
+ equirectangular_to_direction(sl->light_direction, u, v);
+ SWAP(float, sl->light_direction[0], sl->light_direction[1]);
+ normalize_v3(sl->light_direction);
+ negate_v3(sl->light_direction);
+ best_light = new_light;
+ }
+ color += 4;
+ }
+ }
+ }
+ }
+ sl->flag |= STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED;
+}
+
+static StudioLight *studiolight_add_file(const char *path, int flag)
+{
+ char filename[FILE_MAXFILE];
+ BLI_split_file_part(path, filename, FILE_MAXFILE);
+ if (BLI_path_extension_check_array(filename, imb_ext_image)) {
+ StudioLight *sl = studiolight_create(STUDIOLIGHT_EXTERNAL_FILE | flag);
+ BLI_strncpy(sl->name, filename, FILE_MAXFILE);
+ BLI_strncpy(sl->path, path, FILE_MAXFILE);
+ sl->path_irr_cache = BLI_string_joinN(path, ".irr");
+ sl->path_sh_cache = BLI_string_joinN(path, ".sh2");
+ BLI_addtail(&studiolights, sl);
+ return sl;
+ }
+ return NULL;
+}
+
+static void studiolight_add_files_from_datafolder(const int folder_id, const char *subfolder, int flag)
+{
+ struct direntry *dir;
+ const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
+ if (folder) {
+ uint totfile = BLI_filelist_dir_contents(folder, &dir);
+ int i;
+ for (i = 0; i < totfile; i++) {
+ if ((dir[i].type & S_IFREG)) {
+ studiolight_add_file(dir[i].path, flag);
+ }
+ }
+ BLI_filelist_free(dir, totfile);
+ dir = NULL;
+ }
+}
+
+static int studiolight_flag_cmp_order(const StudioLight *sl)
+{
+ /* Internal studiolights before external studio lights */
+ if (sl->flag & STUDIOLIGHT_EXTERNAL_FILE) {
+ return 1;
+ }
+ return 0;
+}
+
+static int studiolight_cmp(const void *a, const void *b)
+{
+ const StudioLight *sl1 = a;
+ const StudioLight *sl2 = b;
+
+ const int flagorder1 = studiolight_flag_cmp_order(sl1);
+ const int flagorder2 = studiolight_flag_cmp_order(sl2);
+
+ if (flagorder1 < flagorder2) {
+ return -1;
+ }
+ else if (flagorder1 > flagorder2) {
+ return 1;
+ }
+ else {
+ return BLI_strcasecmp(sl1->name, sl2->name);
+ }
+}
+
+/* icons */
+
+/* Takes normalized uvs as parameter (range from 0 to 1).
+ * inner_edge and outer_edge are distances (from the center)
+ * in uv space for the alpha mask falloff. */
+static uint alpha_circle_mask(float u, float v, float inner_edge, float outer_edge)
+{
+ /* Coords from center. */
+ float co[2] = {u - 0.5f, v - 0.5f};
+ float dist = len_v2(co);
+ float alpha = 1.0f + (inner_edge - dist) / (outer_edge - inner_edge);
+ uint mask = (uint)floorf(255.0f * min_ff(max_ff(alpha, 0.0f), 1.0f));
+ return mask << 24;
+}
+
+#define STUDIOLIGHT_DIAMETER 0.95f
+
+static void studiolight_radiance_preview(uint *icon_buffer, StudioLight *sl)
+{
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+
+ float pixel_size = 1.0f / (float)STUDIOLIGHT_ICON_SIZE;
+
+ int offset = 0;
+ for (int y = 0; y < STUDIOLIGHT_ICON_SIZE; y++) {
+ float dy = (y + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+ for (int x = 0; x < STUDIOLIGHT_ICON_SIZE; x++) {
+ float dx = (x + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+
+ uint pixelresult = 0x0;
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f);
+ if (alphamask != 0) {
+ float incoming[3] = {0.0f, 0.0f, -1.0f};
+
+ float normal[3];
+ normal[0] = dx * 2.0f - 1.0f;
+ normal[1] = dy * 2.0f - 1.0f;
+ float dist = len_v2(normal);
+ normal[2] = sqrtf(1.0f - SQUARE(dist));
+
+ float direction[3];
+ reflect_v3_v3v3(direction, incoming, normal);
+
+ /* We want to see horizon not poles. */
+ SWAP(float, direction[1], direction[2]);
+ direction[1] = -direction[1];
+
+ float color[4];
+ studiolight_calculate_radiance(sl->equirectangular_radiance_buffer, color, direction);
+
+ pixelresult = rgb_to_cpack(
+ linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ icon_buffer[offset++] = pixelresult;
+ }
+ }
+}
+
+static void studiolight_matcap_preview(uint *icon_buffer, StudioLight *sl, bool flipped)
+{
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_EXTERNAL_IMAGE_LOADED);
+
+ float color[4];
+ float fx, fy;
+ float pixel_size = 1.0f / (float)STUDIOLIGHT_ICON_SIZE;
+ int offset = 0;
+ ImBuf *ibuf = sl->equirectangular_radiance_buffer;
+
+ for (int y = 0; y < STUDIOLIGHT_ICON_SIZE; y++) {
+ fy = (y + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ fy = fy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+ for (int x = 0; x < STUDIOLIGHT_ICON_SIZE; x++) {
+ fx = (x + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ fx = fx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+ if (flipped) {
+ fx = 1.0f - fx;
+ }
+ nearest_interpolation_color(ibuf, NULL, color, fx * ibuf->x - 1.0f, fy * ibuf->y - 1.0f);
+
+ uint alphamask = alpha_circle_mask(fx, fy, 0.5f - pixel_size, 0.5f);
+
+ icon_buffer[offset++] = rgb_to_cpack(
+ linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ }
+}
+
+static void studiolight_irradiance_preview(uint *icon_buffer, StudioLight *sl)
+{
+ BKE_studiolight_ensure_flag(sl, STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED);
+
+ float pixel_size = 1.0f / (float)STUDIOLIGHT_ICON_SIZE;
+
+ int offset = 0;
+ for (int y = 0; y < STUDIOLIGHT_ICON_SIZE; y++) {
+ float dy = (y + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ dy = dy / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+ for (int x = 0; x < STUDIOLIGHT_ICON_SIZE; x++) {
+ float dx = (x + 0.5f) / (float)STUDIOLIGHT_ICON_SIZE;
+ dx = dx / STUDIOLIGHT_DIAMETER - (1.0f - STUDIOLIGHT_DIAMETER) / 2.0f;
+
+ uint pixelresult = 0x0;
+ uint alphamask = alpha_circle_mask(dx, dy, 0.5f - pixel_size, 0.5f);
+ if (alphamask != 0) {
+ /* calculate normal */
+ float normal[3];
+ normal[0] = dx * 2.0f - 1.0f;
+ normal[1] = -(dy * 2.0f - 1.0f);
+ float dist = len_v2(normal);
+ normal[2] = -sqrtf(1.0f - SQUARE(dist));
+ SWAP(float, normal[1], normal[2]);
+
+ float color[3];
+ studiolight_sample_spherical_harmonics(sl, color, normal);
+ pixelresult = rgb_to_cpack(
+ linearrgb_to_srgb(color[0]),
+ linearrgb_to_srgb(color[1]),
+ linearrgb_to_srgb(color[2])) | alphamask;
+ }
+ icon_buffer[offset++] = pixelresult;
+ }
+ }
+}
+
+/* API */
+void BKE_studiolight_init(void)
+{
+ StudioLight *sl;
+ /* go over the preset folder and add a studiolight for every image with its path */
+ /* order studio lights by name */
+ /* Also reserve icon space for it. */
+ /* Add default studio light */
+ sl = studiolight_create(STUDIOLIGHT_INTERNAL | STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED | STUDIOLIGHT_ORIENTATION_CAMERA);
+ BLI_strncpy(sl->name, "Default", FILE_MAXFILE);
+
+
+ copy_v3_fl3(sl->spherical_harmonics_coefs[0], 1.03271556f, 1.07163882f, 1.11193657f);
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 0
+ copy_v3_fl3(sl->spherical_harmonics_coefs[1], -0.00480952f, 0.05290511f, 0.16394117f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[2], -0.29686999f, -0.27378261f, -0.24797194f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[3], 0.47932500f, 0.48242140f, 0.47190312f);
+#endif
+#if STUDIOLIGHT_SPHERICAL_HARMONICS_LEVEL > 1
+ copy_v3_fl3(sl->spherical_harmonics_coefs[4], -0.00576984f, 0.00504886f, 0.01640534f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[5], 0.15500379f, 0.15415503f, 0.16244425f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[6], -0.02483751f, -0.02245096f, -0.00536885f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[7], 0.11155496f, 0.11005443f, 0.10839636f);
+ copy_v3_fl3(sl->spherical_harmonics_coefs[8], 0.01363425f, 0.01278363f, -0.00159006f);
+#endif
+
+ BLI_addtail(&studiolights, sl);
+
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_CAMERA_FOLDER, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_USER_DEFINED);
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_WORLD_FOLDER, STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_USER_DEFINED);
+ studiolight_add_files_from_datafolder(BLENDER_SYSTEM_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL);
+ studiolight_add_files_from_datafolder(BLENDER_USER_DATAFILES, STUDIOLIGHT_MATCAP_FOLDER, STUDIOLIGHT_ORIENTATION_VIEWNORMAL | STUDIOLIGHT_USER_DEFINED);
+
+ /* sort studio lights on filename. */
+ BLI_listbase_sort(&studiolights, studiolight_cmp);
+}
+
+void BKE_studiolight_free(void)
+{
+ struct StudioLight *sl;
+ while ((sl = BLI_pophead(&studiolights))) {
+ studiolight_free(sl);
+ }
+}
+
+struct StudioLight *BKE_studiolight_find_first(int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if ((sl->flag & flag)) {
+ return sl;
+ }
+ }
+ return NULL;
+}
+
+struct StudioLight *BKE_studiolight_find(const char *name, int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if (STREQLEN(sl->name, name, FILE_MAXFILE)) {
+ if ((sl->flag & flag)) {
+ return sl;
+ }
+ else {
+ /* flags do not match, so use default */
+ return BKE_studiolight_find_first(flag);
+ }
+ }
+ }
+ /* When not found, use the default studio light */
+ return BKE_studiolight_find_first(flag);
+}
+
+struct StudioLight *BKE_studiolight_findindex(int index, int flag)
+{
+ LISTBASE_FOREACH(StudioLight *, sl, &studiolights) {
+ if (sl->index == index) {
+ return sl;
+ }
+ }
+ /* When not found, use the default studio light */
+ return BKE_studiolight_find_first(flag);
+}
+
+struct ListBase *BKE_studiolight_listbase(void)
+{
+ return &studiolights;
+}
+
+void BKE_studiolight_preview(uint *icon_buffer, StudioLight *sl, int icon_id_type)
+{
+ switch (icon_id_type) {
+ case STUDIOLIGHT_ICON_ID_TYPE_RADIANCE:
+ default:
+ {
+ studiolight_radiance_preview(icon_buffer, sl);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_IRRADIANCE:
+ {
+ studiolight_irradiance_preview(icon_buffer, sl);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_MATCAP:
+ {
+ studiolight_matcap_preview(icon_buffer, sl, false);
+ break;
+ }
+ case STUDIOLIGHT_ICON_ID_TYPE_MATCAP_FLIPPED:
+ {
+ studiolight_matcap_preview(icon_buffer, sl, true);
+ break;
+ }
+ }
+}
+
+/* Ensure state of Studiolights */
+void BKE_studiolight_ensure_flag(StudioLight *sl, int flag)
+{
+ if ((sl->flag & flag) == flag) {
+ return;
+ }
+
+ if ((flag & STUDIOLIGHT_EXTERNAL_IMAGE_LOADED)) {
+ studiolight_load_equirectangular_image(sl);
+ }
+ if ((flag & STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED)) {
+ studiolight_calculate_radiance_cubemap_buffers(sl);
+ }
+ if ((flag & STUDIOLIGHT_SPHERICAL_HARMONICS_COEFFICIENTS_CALCULATED)) {
+ if (!studiolight_load_spherical_harmonics_coefficients(sl)) {
+ studiolight_calculate_diffuse_light(sl);
+ }
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_RADIANCE_GPUTEXTURE)) {
+ studiolight_create_equirectangular_radiance_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_LIGHT_DIRECTION_CALCULATED)) {
+ studiolight_calculate_light_direction(sl);
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE)) {
+ studiolight_create_equirectangular_irradiance_gputexture(sl);
+ }
+ if ((flag & STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_IMAGE_CALCULATED)) {
+ if (!studiolight_load_irradiance_equirectangular_image(sl)) {
+ studiolight_calculate_irradiance_equirectangular_image(sl);
+ }
+ }
+}
+
+/*
+ * Python API Functions
+ */
+void BKE_studiolight_remove(StudioLight *sl)
+{
+ if (sl->flag & STUDIOLIGHT_USER_DEFINED) {
+ BLI_remlink(&studiolights, sl);
+ studiolight_free(sl);
+ }
+}
+
+StudioLight *BKE_studiolight_new(const char *path, int orientation)
+{
+ StudioLight *sl = studiolight_add_file(path, orientation | STUDIOLIGHT_USER_DEFINED);
+ return sl;
+}
+
+void BKE_studiolight_refresh(void)
+{
+ BKE_studiolight_free();
+ BKE_studiolight_init();
+}
+
+void BKE_studiolight_set_free_function(StudioLight *sl, StudioLightFreeFunction *free_function, void *data)
+{
+ sl->free_function = free_function;
+ sl->free_function_data = data;
+}
+
+void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id)
+{
+ BLI_assert(sl != NULL);
+ if (sl->icon_id_radiance == icon_id) {
+ sl->icon_id_radiance = 0;
+ }
+ if (sl->icon_id_irradiance == icon_id) {
+ sl->icon_id_irradiance = 0;
+ }
+ if (sl->icon_id_matcap == icon_id) {
+ sl->icon_id_matcap = 0;
+ }
+ if (sl->icon_id_matcap_flipped == icon_id) {
+ sl->icon_id_matcap_flipped = 0;
+ }
+}
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
new file mode 100644
index 00000000000..b2736ed8f37
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -0,0 +1,149 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "subdiv_converter.h"
+
+#include "opensubdiv_capi.h"
+#include "opensubdiv_converter_capi.h"
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
+
+eSubdivFVarLinearInterpolation
+BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
+{
+ switch (uv_smooth) {
+ case SUBSURF_UV_SMOOTH_NONE:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
+ case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
+ case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS;
+ case SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE;
+ case SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
+ case SUBSURF_UV_SMOOTH_ALL:
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE;
+ }
+ BLI_assert(!"Unknown uv smooth flag");
+ return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
+}
+
+Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
+ struct OpenSubdiv_Converter *converter)
+{
+ SubdivStats stats;
+ BKE_subdiv_stats_init(&stats);
+ BKE_subdiv_stats_begin(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
+ OpenSubdiv_TopologyRefinerSettings topology_refiner_settings;
+ topology_refiner_settings.level = settings->level;
+ topology_refiner_settings.is_adaptive = settings->is_adaptive;
+ struct OpenSubdiv_TopologyRefiner *osd_topology_refiner = NULL;
+ if (converter->getNumVertices(converter) != 0) {
+ osd_topology_refiner =
+ openSubdiv_createTopologyRefinerFromConverter(
+ converter, &topology_refiner_settings);
+
+ }
+ else {
+ /* TODO(sergey): Check whether original geometry had any vertices.
+ * The thing here is: OpenSubdiv can only deal with faces, but our
+ * side of subdiv also deals with loose vertices and edges.
+ */
+ }
+ Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr");
+ subdiv->settings = *settings;
+ subdiv->topology_refiner = osd_topology_refiner;
+ subdiv->evaluator = NULL;
+ subdiv->displacement_evaluator = NULL;
+ BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
+ subdiv->stats = stats;
+ return subdiv;
+}
+
+Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings,
+ struct Mesh *mesh)
+{
+ if (mesh->totvert == 0) {
+ return NULL;
+ }
+ OpenSubdiv_Converter converter;
+ BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
+ Subdiv *subdiv = BKE_subdiv_new_from_converter(settings, &converter);
+ BKE_subdiv_converter_free(&converter);
+ return subdiv;
+}
+
+void BKE_subdiv_free(Subdiv *subdiv)
+{
+ if (subdiv->evaluator != NULL) {
+ openSubdiv_deleteEvaluator(subdiv->evaluator);
+ }
+ if (subdiv->topology_refiner != NULL) {
+ openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
+ }
+ BKE_subdiv_displacement_detach(subdiv);
+ if (subdiv->cache_.face_ptex_offset != NULL) {
+ MEM_freeN(subdiv->cache_.face_ptex_offset);
+ }
+ MEM_freeN(subdiv);
+}
+
+int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
+{
+ if (subdiv->cache_.face_ptex_offset != NULL) {
+ return subdiv->cache_.face_ptex_offset;
+ }
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ if (topology_refiner == NULL) {
+ return NULL;
+ }
+ const int num_coarse_faces =
+ topology_refiner->getNumFaces(topology_refiner);
+ subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
+ num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
+ int ptex_offset = 0;
+ for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
+ const int num_ptex_faces =
+ topology_refiner->getNumFacePtexFaces(
+ topology_refiner, face_index);
+ subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
+ ptex_offset += num_ptex_faces;
+ }
+ return subdiv->cache_.face_ptex_offset;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
new file mode 100644
index 00000000000..e488b1129fc
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -0,0 +1,1188 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_ccg.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_ccg.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math_bits.h"
+#include "BLI_math_vector.h"
+#include "BLI_task.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_ccg.h"
+#include "BKE_mesh.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+
+#include "opensubdiv_topology_refiner_capi.h"
+
+/* =============================================================================
+ * Generally useful internal helpers.
+ */
+
+/* Number of floats in per-vertex elements. */
+static int num_element_float_get(const SubdivCCG *subdiv_ccg)
+{
+ /* We always have 3 floats for coordinate. */
+ int num_floats = 3;
+ if (subdiv_ccg->has_normal) {
+ num_floats += 3;
+ }
+ if (subdiv_ccg->has_mask) {
+ num_floats += 1;
+ }
+ return num_floats;
+}
+
+/* Per-vertex element size in bytes. */
+static int element_size_bytes_get(const SubdivCCG *subdiv_ccg)
+{
+ return sizeof(float) * num_element_float_get(subdiv_ccg);
+}
+
+/* =============================================================================
+ * Internal helpers for CCG creation.
+ */
+
+static void subdiv_ccg_init_layers(SubdivCCG *subdiv_ccg,
+ const SubdivToCCGSettings *settings)
+{
+ /* CCG always contains coordinates. Rest of layers are coming after them. */
+ int layer_offset = sizeof(float) * 3;
+ /* Mask. */
+ if (settings->need_mask) {
+ subdiv_ccg->has_mask = true;
+ subdiv_ccg->mask_offset = layer_offset;
+ layer_offset += sizeof(float);
+ }
+ else {
+ subdiv_ccg->has_mask = false;
+ subdiv_ccg->mask_offset = -1;
+ }
+ /* Normals.
+ *
+ * NOTE: Keep them at the end, matching old CCGDM. Doesn't really matter
+ * here, but some other area might in theory depend memory layout.
+ */
+ if (settings->need_normal) {
+ subdiv_ccg->has_normal = true;
+ subdiv_ccg->normal_offset = layer_offset;
+ layer_offset += sizeof(float) * 3;
+ }
+ else {
+ subdiv_ccg->has_normal = false;
+ subdiv_ccg->normal_offset = -1;
+ }
+}
+
+/* TODO(sergey): Make it more accessible function. */
+static int topology_refiner_count_face_corners(
+ OpenSubdiv_TopologyRefiner *topology_refiner)
+{
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ int num_corners = 0;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ num_corners += topology_refiner->getNumFaceVertices(
+ topology_refiner, face_index);
+ }
+ return num_corners;
+}
+
+/* NOTE: Grid size and layer flags are to be filled in before calling this
+ * function.
+ */
+static void subdiv_ccg_alloc_elements(SubdivCCG *subdiv_ccg, Subdiv *subdiv)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int element_size = element_size_bytes_get(subdiv_ccg);
+ /* Allocate memory for surface grids. */
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ const int num_grids = topology_refiner_count_face_corners(topology_refiner);
+ const int grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
+ const int grid_area = grid_size * grid_size;
+ subdiv_ccg->num_grids = num_grids;
+ subdiv_ccg->grids =
+ MEM_calloc_arrayN(num_grids, sizeof(CCGElem *), "subdiv ccg grids");
+ subdiv_ccg->grids_storage = MEM_calloc_arrayN(
+ num_grids, ((size_t)grid_area) * element_size,
+ "subdiv ccg grids storage");
+ const size_t grid_size_in_bytes = (size_t)grid_area * element_size;
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ const size_t grid_offset = grid_size_in_bytes * grid_index;
+ subdiv_ccg->grids[grid_index] =
+ (CCGElem *)&subdiv_ccg->grids_storage[grid_offset];
+ }
+ /* Grid material flags. */
+ subdiv_ccg->grid_flag_mats = MEM_calloc_arrayN(
+ num_grids, sizeof(DMFlagMat), "ccg grid material flags");
+ /* Grid hidden flags. */
+ subdiv_ccg->grid_hidden = MEM_calloc_arrayN(
+ num_grids, sizeof(BLI_bitmap *), "ccg grid material flags");
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ subdiv_ccg->grid_hidden[grid_index] =
+ BLI_BITMAP_NEW(grid_area, "ccg grid hidden");
+ }
+ /* TODO(sergey): Allocate memory for loose elements. */
+ /* Allocate memory for faces. */
+ subdiv_ccg->num_faces = num_faces;
+ if (num_faces) {
+ subdiv_ccg->faces = MEM_calloc_arrayN(
+ num_faces, sizeof(SubdivCCGFace), "Subdiv CCG faces");
+ subdiv_ccg->grid_faces = MEM_calloc_arrayN(
+ num_grids, sizeof(SubdivCCGFace *), "Subdiv CCG grid faces");
+ }
+}
+
+/* =============================================================================
+ * Grids evaluation.
+ */
+
+typedef struct CCGEvalGridsData {
+ SubdivCCG *subdiv_ccg;
+ Subdiv *subdiv;
+ int *face_ptex_offset;
+ SubdivCCGMask *mask_evaluator;
+} CCGEvalGridsData;
+
+static void subdiv_ccg_eval_grid_element(
+ CCGEvalGridsData *data,
+ const int ptex_face_index,
+ const float u, const float v,
+ unsigned char *element)
+{
+ Subdiv *subdiv = data->subdiv;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ if (subdiv->displacement_evaluator != NULL) {
+ BKE_subdiv_eval_final_point(
+ subdiv, ptex_face_index, u, v, (float *)element);
+ }
+ else if (subdiv_ccg->has_normal) {
+ BKE_subdiv_eval_limit_point_and_normal(
+ subdiv, ptex_face_index, u, v,
+ (float *)element,
+ (float *)(element + subdiv_ccg->normal_offset));
+ }
+ else {
+ BKE_subdiv_eval_limit_point(
+ subdiv, ptex_face_index, u, v, (float *)element);
+ }
+ if (subdiv_ccg->has_mask) {
+ float *mask_value_ptr = (float *)(element + subdiv_ccg->mask_offset);
+ if (data->mask_evaluator != NULL) {
+ *mask_value_ptr = data->mask_evaluator->eval_mask(
+ data->mask_evaluator, ptex_face_index, u, v);
+ }
+ else {
+ *mask_value_ptr = 0.0f;
+ }
+ }
+}
+
+BLI_INLINE void rotate_corner_to_quad(
+ const int corner,
+ const float u, const float v,
+ float *r_u, float *r_v)
+{
+ if (corner == 0) {
+ *r_u = 0.5f - v * 0.5f;
+ *r_v = 0.5f - u * 0.5f;
+ }
+ else if (corner == 1) {
+ *r_u = 0.5f + u * 0.5f;
+ *r_v = 0.5f - v * 0.5f;
+ }
+ else if (corner == 2) {
+ *r_u = 0.5f + v * 0.5f;
+ *r_v = 0.5f + u * 0.5f;
+ }
+ else {
+ BLI_assert(corner == 3);
+ *r_u = 0.5f - u * 0.5f;
+ *r_v = 0.5f + v * 0.5f;
+ }
+}
+
+static void subdiv_ccg_eval_regular_grid(CCGEvalGridsData *data,
+ const int face_index)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ const int ptex_face_index = data->face_ptex_offset[face_index];
+ const int grid_size = subdiv_ccg->grid_size;
+ const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
+ const int element_size = element_size_bytes_get(subdiv_ccg);
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
+ const SubdivCCGFace *face = &faces[face_index];
+ for (int corner = 0; corner < face->num_grids; corner++) {
+ const int grid_index = face->start_grid_index + corner;
+ unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
+ for (int y = 0; y < grid_size; y++) {
+ const float grid_v = (float)y * grid_size_1_inv;
+ for (int x = 0; x < grid_size; x++) {
+ const float grid_u = (float)x * grid_size_1_inv;
+ float u, v;
+ rotate_corner_to_quad(corner, grid_u, grid_v, &u, &v);
+ const size_t grid_element_index = (size_t)y * grid_size + x;
+ const size_t grid_element_offset =
+ grid_element_index * element_size;
+ subdiv_ccg_eval_grid_element(
+ data,
+ ptex_face_index, u, v,
+ &grid[grid_element_offset]);
+ }
+ }
+ /* Assign grid's face. */
+ grid_faces[grid_index] = &faces[face_index];
+ }
+}
+
+static void subdiv_ccg_eval_special_grid(CCGEvalGridsData *data,
+ const int face_index)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ const int grid_size = subdiv_ccg->grid_size;
+ const float grid_size_1_inv = 1.0f / (float)(grid_size - 1);
+ const int element_size = element_size_bytes_get(subdiv_ccg);
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ SubdivCCGFace **grid_faces = subdiv_ccg->grid_faces;
+ const SubdivCCGFace *face = &faces[face_index];
+ for (int corner = 0; corner < face->num_grids; corner++) {
+ const int grid_index = face->start_grid_index + corner;
+ unsigned char *grid = (unsigned char *)subdiv_ccg->grids[grid_index];
+ for (int y = 0; y < grid_size; y++) {
+ const float u = 1.0f - ((float)y * grid_size_1_inv);
+ for (int x = 0; x < grid_size; x++) {
+ const float v = 1.0f - ((float)x * grid_size_1_inv);
+ const int ptex_face_index =
+ data->face_ptex_offset[face_index] + corner;
+ const size_t grid_element_index = (size_t)y * grid_size + x;
+ const size_t grid_element_offset =
+ grid_element_index * element_size;
+ subdiv_ccg_eval_grid_element(
+ data,
+ ptex_face_index, u, v,
+ &grid[grid_element_offset]);
+ }
+ }
+ /* Assign grid's face. */
+ grid_faces[grid_index] = &faces[face_index];
+ }
+}
+
+static void subdiv_ccg_eval_grids_task(
+ void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ CCGEvalGridsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ SubdivCCGFace *face = &subdiv_ccg->faces[face_index];
+ if (face->num_grids == 4) {
+ subdiv_ccg_eval_regular_grid(data, face_index);
+ }
+ else {
+ subdiv_ccg_eval_special_grid(data, face_index);
+ }
+}
+
+static bool subdiv_ccg_evaluate_grids(
+ SubdivCCG *subdiv_ccg,
+ Subdiv *subdiv,
+ SubdivCCGMask *mask_evaluator)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ /* Initialize data passed to all the tasks. */
+ CCGEvalGridsData data;
+ data.subdiv_ccg = subdiv_ccg;
+ data.subdiv = subdiv;
+ data.face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+ data.mask_evaluator = mask_evaluator;
+ /* Threaded grids evaluation. */
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ BLI_task_parallel_range(0, num_faces,
+ &data,
+ subdiv_ccg_eval_grids_task,
+ &parallel_range_settings);
+ /* If displacement is used, need to calculate normals after all final
+ * coordinates are known.
+ */
+ if (subdiv->displacement_evaluator != NULL) {
+ BKE_subdiv_ccg_recalc_normals(subdiv_ccg);
+ }
+ return true;
+}
+
+/* Initialize face descriptors, assuming memory for them was already
+ * allocated.
+ */
+static void subdiv_ccg_init_faces(SubdivCCG *subdiv_ccg)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_faces = subdiv_ccg->num_faces;
+ int corner_index = 0;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ const int num_corners = topology_refiner->getNumFaceVertices(
+ topology_refiner, face_index);
+ subdiv_ccg->faces[face_index].num_grids = num_corners;
+ subdiv_ccg->faces[face_index].start_grid_index = corner_index;
+ corner_index += num_corners;
+ }
+}
+
+/* TODO(sergey): Consider making it generic enough to be fit into BLI. */
+typedef struct StaticOrHeapIntStorage {
+ int static_storage[64];
+ int static_storage_size;
+ int *heap_storage;
+ int heap_storage_size;
+} StaticOrHeapIntStorage;
+
+static void static_or_heap_storage_init(StaticOrHeapIntStorage *storage)
+{
+ storage->static_storage_size =
+ sizeof(storage->static_storage) / sizeof(*storage->static_storage);
+ storage->heap_storage = NULL;
+ storage->heap_storage_size = 0;
+}
+
+static int *static_or_heap_storage_get(StaticOrHeapIntStorage *storage,
+ int size)
+{
+ /* Requested size small enough to be fit into stack allocated memory. */
+ if (size <= storage->static_storage_size) {
+ return storage->static_storage;
+ }
+ /* Make sure heap ius big enough. */
+ if (size > storage->heap_storage_size) {
+ MEM_SAFE_FREE(storage->heap_storage);
+ storage->heap_storage = MEM_malloc_arrayN(
+ size, sizeof(int), "int storage");
+ storage->heap_storage_size = size;
+ }
+ return storage->heap_storage;
+}
+
+static void static_or_heap_storage_free(StaticOrHeapIntStorage *storage)
+{
+ MEM_SAFE_FREE(storage->heap_storage);
+}
+
+static void subdiv_ccg_allocate_adjacent_edges(SubdivCCG *subdiv_ccg,
+ const int num_edges)
+{
+ subdiv_ccg->num_adjacent_edges = num_edges;
+ subdiv_ccg->adjacent_edges = MEM_calloc_arrayN(
+ subdiv_ccg->num_adjacent_edges,
+ sizeof(*subdiv_ccg->adjacent_edges),
+ "ccg adjacent edges");
+}
+
+/* Returns storage where boundary elements are to be stored. */
+static CCGElem **subdiv_ccg_adjacent_edge_add_face(
+ SubdivCCG *subdiv_ccg,
+ SubdivCCGAdjacentEdge *adjacent_edge,
+ SubdivCCGFace *face)
+{
+ const int grid_size = subdiv_ccg->grid_size * 2;
+ const int adjacent_face_index = adjacent_edge->num_adjacent_faces;
+ ++adjacent_edge->num_adjacent_faces;
+ /* Store new adjacent face. */
+ adjacent_edge->faces = MEM_reallocN(
+ adjacent_edge->faces,
+ adjacent_edge->num_adjacent_faces * sizeof(*adjacent_edge->faces));
+ adjacent_edge->faces[adjacent_face_index] = face;
+ /* Allocate memory for the boundary elements. */
+ adjacent_edge->boundary_elements = MEM_reallocN(
+ adjacent_edge->boundary_elements,
+ adjacent_edge->num_adjacent_faces *
+ sizeof(*adjacent_edge->boundary_elements));
+ adjacent_edge->boundary_elements[adjacent_face_index] =
+ MEM_malloc_arrayN(
+ grid_size * 2, sizeof(CCGElem *), "ccg adjacent boundary");
+ return adjacent_edge->boundary_elements[adjacent_face_index];
+}
+
+static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG *subdiv_ccg)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_edges = topology_refiner->getNumEdges(topology_refiner);
+ const int grid_size = subdiv_ccg->grid_size;
+ if (num_edges == 0) {
+ /* Early output, nothing to do in this case. */
+ return;
+ }
+ subdiv_ccg_allocate_adjacent_edges(subdiv_ccg, num_edges);
+ /* Initialize storage. */
+ StaticOrHeapIntStorage face_vertices_storage;
+ StaticOrHeapIntStorage face_edges_storage;
+ static_or_heap_storage_init(&face_vertices_storage);
+ static_or_heap_storage_init(&face_edges_storage);
+ /* Key to access elements. */
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ /* Store adjacency for all faces. */
+ const int num_faces = subdiv_ccg->num_faces;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ SubdivCCGFace *face = &faces[face_index];
+ const int num_face_grids = face->num_grids;
+ const int num_face_edges = num_face_grids;
+ int *face_vertices = static_or_heap_storage_get(
+ &face_vertices_storage, num_face_edges);
+ topology_refiner->getFaceVertices(
+ topology_refiner, face_index, face_vertices);
+ /* Note that order of edges is same as order of MLoops, which also
+ * means it's the same as order of grids.
+ */
+ int *face_edges = static_or_heap_storage_get(
+ &face_edges_storage, num_face_edges);
+ topology_refiner->getFaceEdges(
+ topology_refiner, face_index, face_edges);
+ /* Store grids adjacency for this edge. */
+ for (int corner = 0; corner < num_face_edges; corner++) {
+ const int vertex_index = face_vertices[corner];
+ const int edge_index = face_edges[corner];
+ int edge_vertices[2];
+ topology_refiner->getEdgeVertices(
+ topology_refiner, edge_index, edge_vertices);
+ const bool is_edge_flipped = (edge_vertices[0] != vertex_index);
+ /* Grid which is adjacent to the current corner. */
+ const int current_grid_index = face->start_grid_index + corner;
+ CCGElem *current_grid = subdiv_ccg->grids[current_grid_index];
+ /* Grid which is adjacent to the next corner. */
+ const int next_grid_index =
+ face->start_grid_index + (corner + 1) % num_face_grids;
+ CCGElem *next_grid = subdiv_ccg->grids[next_grid_index];
+ /* Add new face to the adjacent edge. */
+ SubdivCCGAdjacentEdge *adjacent_edge =
+ &subdiv_ccg->adjacent_edges[edge_index];
+ CCGElem **boundary_elements = subdiv_ccg_adjacent_edge_add_face(
+ subdiv_ccg, adjacent_edge, face);
+ /* Fill CCG elements along the edge. */
+ int boundary_element_index = 0;
+ if (is_edge_flipped) {
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] =
+ CCG_grid_elem(&key,
+ next_grid,
+ grid_size - i - 1,
+ grid_size - 1);
+ }
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] =
+ CCG_grid_elem(&key,
+ current_grid,
+ grid_size - 1,
+ i);
+ }
+ }
+ else {
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] =
+ CCG_grid_elem(&key,
+ current_grid,
+ grid_size - 1,
+ grid_size - i - 1);
+ }
+ for (int i = 0; i < grid_size; i++) {
+ boundary_elements[boundary_element_index++] =
+ CCG_grid_elem(&key,
+ next_grid,
+ i,
+ grid_size - 1);
+ }
+ }
+ }
+ }
+ /* Free possibly heap-allocated storage. */
+ static_or_heap_storage_free(&face_vertices_storage);
+ static_or_heap_storage_free(&face_edges_storage);
+}
+
+static void subdiv_ccg_allocate_adjacent_vertices(SubdivCCG *subdiv_ccg,
+ const int num_vertices)
+{
+ subdiv_ccg->num_adjacent_vertices = num_vertices;
+ subdiv_ccg->adjacent_vertices = MEM_calloc_arrayN(
+ subdiv_ccg->num_adjacent_vertices,
+ sizeof(*subdiv_ccg->adjacent_vertices),
+ "ccg adjacent vertices");
+}
+
+/* Returns storage where corner elements are to be stored. This is a pointer
+ * to the actual storage.
+ */
+static CCGElem **subdiv_ccg_adjacent_vertex_add_face(
+ SubdivCCGAdjacentVertex *adjacent_vertex,
+ SubdivCCGFace *face)
+{
+ const int adjacent_face_index = adjacent_vertex->num_adjacent_faces;
+ ++adjacent_vertex->num_adjacent_faces;
+ /* Store new adjacent face. */
+ adjacent_vertex->faces = MEM_reallocN(
+ adjacent_vertex->faces,
+ adjacent_vertex->num_adjacent_faces *
+ sizeof(*adjacent_vertex->faces));
+ adjacent_vertex->faces[adjacent_face_index] = face;
+ /* Allocate memory for the boundary elements. */
+ adjacent_vertex->corner_elements = MEM_reallocN(
+ adjacent_vertex->corner_elements,
+ adjacent_vertex->num_adjacent_faces *
+ sizeof(*adjacent_vertex->corner_elements));
+ return &adjacent_vertex->corner_elements[adjacent_face_index];
+}
+
+static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG *subdiv_ccg)
+{
+ Subdiv *subdiv = subdiv_ccg->subdiv;
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ const int num_vertices =
+ topology_refiner->getNumVertices(topology_refiner);
+ const int grid_size = subdiv_ccg->grid_size;
+ if (num_vertices == 0) {
+ /* Early output, nothing to do in this case. */
+ return;
+ }
+ subdiv_ccg_allocate_adjacent_vertices(subdiv_ccg, num_vertices);
+ /* Initialize storage. */
+ StaticOrHeapIntStorage face_vertices_storage;
+ static_or_heap_storage_init(&face_vertices_storage);
+ /* Key to access elements. */
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ /* Store adjacency for all faces. */
+ const int num_faces = subdiv_ccg->num_faces;
+ for (int face_index = 0; face_index < num_faces; face_index++) {
+ SubdivCCGFace *face = &faces[face_index];
+ const int num_face_grids = face->num_grids;
+ const int num_face_edges = num_face_grids;
+ int *face_vertices = static_or_heap_storage_get(
+ &face_vertices_storage, num_face_edges);
+ topology_refiner->getFaceVertices(
+ topology_refiner, face_index, face_vertices);
+ for (int corner = 0; corner < num_face_edges; corner++) {
+ const int vertex_index = face_vertices[corner];
+ /* Grid which is adjacent to the current corner. */
+ const int grid_index = face->start_grid_index + corner;
+ CCGElem *grid = subdiv_ccg->grids[grid_index];
+ /* Add new face to the adjacent edge. */
+ SubdivCCGAdjacentVertex *adjacent_vertex =
+ &subdiv_ccg->adjacent_vertices[vertex_index];
+ CCGElem **corner_element = subdiv_ccg_adjacent_vertex_add_face(
+ adjacent_vertex, face);
+ *corner_element = CCG_grid_elem(
+ &key, grid, grid_size - 1, grid_size - 1);
+ }
+ }
+ /* Free possibly heap-allocated storage. */
+ static_or_heap_storage_free(&face_vertices_storage);
+}
+
+static void subdiv_ccg_init_faces_neighborhood(SubdivCCG *subdiv_ccg)
+{
+ subdiv_ccg_init_faces_edge_neighborhood(subdiv_ccg);
+ subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg);
+}
+
+/* =============================================================================
+ * Creation / evaluation.
+ */
+
+SubdivCCG *BKE_subdiv_to_ccg(
+ Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ SubdivCCGMask *mask_evaluator)
+{
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ SubdivCCG *subdiv_ccg = MEM_callocN(sizeof(SubdivCCG), "subdiv ccg");
+ subdiv_ccg->subdiv = subdiv;
+ subdiv_ccg->level = bitscan_forward_i(settings->resolution - 1);
+ subdiv_ccg->grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
+ subdiv_ccg_init_layers(subdiv_ccg, settings);
+ subdiv_ccg_alloc_elements(subdiv_ccg, subdiv);
+ subdiv_ccg_init_faces(subdiv_ccg);
+ subdiv_ccg_init_faces_neighborhood(subdiv_ccg);
+ if (!subdiv_ccg_evaluate_grids(subdiv_ccg, subdiv, mask_evaluator)) {
+ BKE_subdiv_ccg_destroy(subdiv_ccg);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ return NULL;
+ }
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ return subdiv_ccg;
+}
+
+Mesh *BKE_subdiv_to_ccg_mesh(
+ Subdiv *subdiv,
+ const SubdivToCCGSettings *settings,
+ const Mesh *coarse_mesh)
+{
+ /* Make sure evaluator is ready. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ if (coarse_mesh->totpoly) {
+ return false;
+ }
+ }
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
+ SubdivCCGMask mask_evaluator;
+ bool has_mask = BKE_subdiv_ccg_mask_init_from_paint(
+ &mask_evaluator, coarse_mesh);
+ SubdivCCG *subdiv_ccg = BKE_subdiv_to_ccg(
+ subdiv, settings, has_mask ? &mask_evaluator : NULL);
+ if (has_mask) {
+ mask_evaluator.free(&mask_evaluator);
+ }
+ if (subdiv_ccg == NULL) {
+ return NULL;
+ }
+ Mesh *result = BKE_mesh_new_nomain_from_template(
+ coarse_mesh, 0, 0, 0, 0, 0);
+ result->runtime.subdiv_ccg = subdiv_ccg;
+ return result;
+}
+
+void BKE_subdiv_ccg_destroy(SubdivCCG *subdiv_ccg)
+{
+ const int num_grids = subdiv_ccg->num_grids;
+ MEM_SAFE_FREE(subdiv_ccg->grids);
+ MEM_SAFE_FREE(subdiv_ccg->grids_storage);
+ MEM_SAFE_FREE(subdiv_ccg->edges);
+ MEM_SAFE_FREE(subdiv_ccg->vertices);
+ MEM_SAFE_FREE(subdiv_ccg->grid_flag_mats);
+ if (subdiv_ccg->grid_hidden != NULL) {
+ for (int grid_index = 0; grid_index < num_grids; grid_index++) {
+ MEM_freeN(subdiv_ccg->grid_hidden[grid_index]);
+ }
+ MEM_freeN(subdiv_ccg->grid_hidden);
+ }
+ if (subdiv_ccg->subdiv != NULL) {
+ BKE_subdiv_free(subdiv_ccg->subdiv);
+ }
+ MEM_SAFE_FREE(subdiv_ccg->faces);
+ MEM_SAFE_FREE(subdiv_ccg->grid_faces);
+ /* Free map of adjacent edges. */
+ for (int i = 0; i < subdiv_ccg->num_adjacent_edges; i++) {
+ SubdivCCGAdjacentEdge *adjacent_edge = &subdiv_ccg->adjacent_edges[i];
+ for (int face_index = 0;
+ face_index < adjacent_edge->num_adjacent_faces;
+ face_index++)
+ {
+ MEM_SAFE_FREE(adjacent_edge->boundary_elements[face_index]);
+ }
+ MEM_SAFE_FREE(adjacent_edge->faces);
+ MEM_SAFE_FREE(adjacent_edge->boundary_elements);
+ }
+ MEM_SAFE_FREE(subdiv_ccg->adjacent_edges);
+ /* Free map of adjacent vertices. */
+ for (int i = 0; i < subdiv_ccg->num_adjacent_vertices; i++) {
+ SubdivCCGAdjacentVertex *adjacent_vertex =
+ &subdiv_ccg->adjacent_vertices[i];
+ MEM_SAFE_FREE(adjacent_vertex->faces);
+ MEM_SAFE_FREE(adjacent_vertex->corner_elements);
+ }
+ MEM_SAFE_FREE(subdiv_ccg->adjacent_vertices);
+ MEM_freeN(subdiv_ccg);
+}
+
+void BKE_subdiv_ccg_key(CCGKey *key, const SubdivCCG *subdiv_ccg, int level)
+{
+ key->level = level;
+ key->elem_size = element_size_bytes_get(subdiv_ccg);
+ key->grid_size = BKE_subdiv_grid_size_from_level(level);
+ key->grid_area = key->grid_size * key->grid_size;
+ key->grid_bytes = key->elem_size * key->grid_area;
+
+ key->normal_offset = subdiv_ccg->normal_offset;
+ key->mask_offset = subdiv_ccg->mask_offset;
+
+ key->has_normals = subdiv_ccg->has_normal;
+ key->has_mask = subdiv_ccg->has_mask;
+}
+
+void BKE_subdiv_ccg_key_top_level(CCGKey *key, const SubdivCCG *subdiv_ccg)
+{
+ BKE_subdiv_ccg_key(key, subdiv_ccg, subdiv_ccg->level);
+}
+
+/* =============================================================================
+ * Normals.
+ */
+
+typedef struct RecalcInnerNormalsData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+} RecalcInnerNormalsData;
+
+typedef struct RecalcInnerNormalsTLSData {
+ float (*face_normals)[3];
+} RecalcInnerNormalsTLSData;
+
+/* Evaluate high-res face normals, for faces which corresponds to grid elements
+ *
+ * {(x, y), {x + 1, y}, {x + 1, y + 1}, {x, y + 1}}
+ *
+ * The result is stored in normals storage from TLS.
+ */
+static void subdiv_ccg_recalc_inner_face_normals(
+ RecalcInnerNormalsData *data,
+ RecalcInnerNormalsTLSData *tls,
+ const int grid_index)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ const int grid_size = subdiv_ccg->grid_size;
+ const int grid_size_1 = grid_size - 1;
+ CCGElem *grid = subdiv_ccg->grids[grid_index];
+ if (tls->face_normals == NULL) {
+ tls->face_normals = MEM_malloc_arrayN(
+ grid_size_1 * grid_size_1,
+ 3 * sizeof(float),
+ "CCG TLS normals");
+ }
+ for (int y = 0; y < grid_size -1; y++) {
+ for (int x = 0; x < grid_size - 1; x++) {
+ CCGElem *grid_elements[4] = {
+ CCG_grid_elem(key, grid, x, y + 1),
+ CCG_grid_elem(key, grid, x + 1, y + 1),
+ CCG_grid_elem(key, grid, x + 1, y),
+ CCG_grid_elem(key, grid, x, y)
+ };
+ float *co[4] = {
+ CCG_elem_co(key, grid_elements[0]),
+ CCG_elem_co(key, grid_elements[1]),
+ CCG_elem_co(key, grid_elements[2]),
+ CCG_elem_co(key, grid_elements[3])
+ };
+ const int face_index = y * grid_size_1 + x;
+ float *face_normal = tls->face_normals[face_index];
+ normal_quad_v3(face_normal, co[0], co[1], co[2], co[3]);
+ }
+ }
+}
+
+/* Average normals at every grid element, using adjacent faces normals. */
+static void subdiv_ccg_average_inner_face_normals(
+ RecalcInnerNormalsData *data,
+ RecalcInnerNormalsTLSData *tls,
+ const int grid_index)
+{
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ const int grid_size = subdiv_ccg->grid_size;
+ const int grid_size_1 = grid_size - 1;
+ CCGElem *grid = subdiv_ccg->grids[grid_index];
+ const float (*face_normals)[3] = tls->face_normals;
+ for (int y = 0; y < grid_size; y++) {
+ for (int x = 0; x < grid_size; x++) {
+ float normal_acc[3] = {0.0f, 0.0f, 0.0f};
+ int counter = 0;
+ /* Accumulate normals of all adjacent faces. */
+ if (x < grid_size_1 && y < grid_size_1) {
+ add_v3_v3(normal_acc, face_normals[y * grid_size_1 + x]);
+ counter++;
+ }
+ if (x >= 1) {
+ if (y < grid_size_1) {
+ add_v3_v3(normal_acc,
+ face_normals[y * grid_size_1 + (x - 1)]);
+ counter++;
+ }
+ if (y >= 1) {
+ add_v3_v3(normal_acc,
+ face_normals[(y - 1) * grid_size_1 + (x - 1)]);
+ counter++;
+ }
+ }
+ if (y >= 1 && x < grid_size_1) {
+ add_v3_v3(normal_acc, face_normals[(y - 1) * grid_size_1 + x]);
+ counter++;
+ }
+ /* Normalize and store. */
+ mul_v3_v3fl(CCG_grid_elem_no(key, grid, x, y),
+ normal_acc,
+ 1.0f / (float)counter);
+ }
+ }
+}
+
+static void subdiv_ccg_recalc_inner_normal_task(
+ void *__restrict userdata_v,
+ const int grid_index,
+ const ParallelRangeTLS *__restrict tls_v)
+{
+ RecalcInnerNormalsData *data = userdata_v;
+ RecalcInnerNormalsTLSData *tls = tls_v->userdata_chunk;
+ subdiv_ccg_recalc_inner_face_normals(data, tls, grid_index);
+ subdiv_ccg_average_inner_face_normals(data, tls, grid_index);
+}
+
+static void subdiv_ccg_recalc_inner_normal_finalize(
+ void *__restrict UNUSED(userdata),
+ void *__restrict tls_v)
+{
+ RecalcInnerNormalsTLSData *tls = tls_v;
+ MEM_SAFE_FREE(tls->face_normals);
+}
+
+/* Recalculate normals which corresponds to non-boundaries elements of grids. */
+static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG *subdiv_ccg)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ RecalcInnerNormalsData data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key
+ };
+ RecalcInnerNormalsTLSData tls_data = {NULL};
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.userdata_chunk = &tls_data;
+ parallel_range_settings.userdata_chunk_size = sizeof(tls_data);
+ parallel_range_settings.func_finalize =
+ subdiv_ccg_recalc_inner_normal_finalize;
+ BLI_task_parallel_range(0, subdiv_ccg->num_grids,
+ &data,
+ subdiv_ccg_recalc_inner_normal_task,
+ &parallel_range_settings);
+}
+
+void BKE_subdiv_ccg_recalc_normals(SubdivCCG *subdiv_ccg)
+{
+ if (!subdiv_ccg->has_normal) {
+ /* Grids don't have normals, can do early output. */
+ return;
+ }
+ subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg);
+ BKE_subdiv_ccg_average_grids(subdiv_ccg);
+}
+
+/* =============================================================================
+ * Boundary averaging/stitching.
+ */
+
+typedef struct AverageInnerGridsData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+} AverageInnerGridsData;
+
+static void average_grid_element_value_v3(float a[3], float b[3])
+{
+ add_v3_v3(a, b);
+ mul_v3_fl(a, 0.5f);
+ copy_v3_v3(b, a);
+}
+
+static void average_grid_element(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ CCGElem *grid_element_a,
+ CCGElem *grid_element_b)
+{
+ average_grid_element_value_v3(CCG_elem_co(key, grid_element_a),
+ CCG_elem_co(key, grid_element_b));
+ if (subdiv_ccg->has_normal) {
+ average_grid_element_value_v3(CCG_elem_no(key, grid_element_a),
+ CCG_elem_no(key, grid_element_b));
+ }
+ if (subdiv_ccg->has_mask) {
+ float mask =
+ (*CCG_elem_mask(key, grid_element_a) +
+ *CCG_elem_mask(key, grid_element_b)) * 0.5f;
+ *CCG_elem_mask(key, grid_element_a) = mask;
+ *CCG_elem_mask(key, grid_element_b) = mask;
+ }
+}
+
+static void copy_grid_element(SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ CCGElem *destination,
+ CCGElem *source)
+{
+ copy_v3_v3(CCG_elem_co(key, destination), CCG_elem_co(key, source));
+ if (subdiv_ccg->has_normal) {
+ copy_v3_v3(CCG_elem_no(key, destination), CCG_elem_no(key, source));
+ }
+ if (subdiv_ccg->has_mask) {
+ *CCG_elem_mask(key, destination) = *CCG_elem_mask(key, source);
+ }
+}
+
+static void subdiv_ccg_average_inner_face_grids(
+ SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGFace *face)
+{
+ CCGElem **grids = subdiv_ccg->grids;
+ const int num_face_grids = face->num_grids;
+ const int grid_size = subdiv_ccg->grid_size;
+ CCGElem *prev_grid = grids[face->start_grid_index + num_face_grids - 1];
+ for (int corner = 0; corner < num_face_grids; corner++) {
+ CCGElem *grid = grids[face->start_grid_index + corner];
+ for (int i = 0; i < grid_size; i++) {
+ CCGElem *prev_grid_element = CCG_grid_elem(key, prev_grid, i, 0);
+ CCGElem *grid_element = CCG_grid_elem(key, grid, 0, i);
+ average_grid_element(
+ subdiv_ccg, key, prev_grid_element, grid_element);
+ }
+ prev_grid = grid;
+ }
+
+}
+
+static void subdiv_ccg_average_inner_grids_task(
+ void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
+{
+ AverageInnerGridsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ SubdivCCGFace *faces = subdiv_ccg->faces;
+ SubdivCCGFace *face = &faces[face_index];
+ subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
+}
+
+typedef struct AverageGridsBoundariesData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+} AverageGridsBoundariesData;
+
+static void subdiv_ccg_average_grids_boundary(
+ SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGAdjacentEdge *adjacent_edge)
+{
+ const int num_adjacent_faces = adjacent_edge->num_adjacent_faces;
+ const int grid_size2 = subdiv_ccg->grid_size * 2;
+ if (num_adjacent_faces == 1) {
+ /* Nothing to average with. */
+ return;
+ }
+ /* Incrementall average result to elements of a first adjacent face.
+ *
+ * Arguably, this is less precise than accumulating and then diving once,
+ * but on another hand this is more stable when coordinates are big.
+ */
+ for (int face_index = 1; face_index < num_adjacent_faces; face_index++) {
+ /* NOTE: We ignore very first and very last elements, they correspond
+ * to corner vertices, and they can belong to multiple edges.
+ * The fact, that they can belong to multiple edges means we can't
+ * safely average them.
+ * The fact, that they correspond to a corner elements, means they will
+ * be handled at the upcoming pass over corner elements.
+ */
+ for (int i = 1; i < grid_size2 - 1; i++) {
+ CCGElem *grid_element_0 =
+ adjacent_edge->boundary_elements[0][i];
+ CCGElem *grid_element_face_index =
+ adjacent_edge->boundary_elements[face_index][i];
+ average_grid_element(subdiv_ccg,
+ key,
+ grid_element_0,
+ grid_element_face_index);
+ }
+ }
+ /* Copy averaged value to all the other faces. */
+ for (int face_index = 1; face_index < num_adjacent_faces; face_index++) {
+ for (int i = 1; i < grid_size2 -1; i++) {
+ CCGElem *grid_element_0 =
+ adjacent_edge->boundary_elements[0][i];
+ CCGElem *grid_element_face_index =
+ adjacent_edge->boundary_elements[face_index][i];
+ copy_grid_element(subdiv_ccg,
+ key,
+ grid_element_face_index,
+ grid_element_0);
+ }
+ }
+}
+
+static void subdiv_ccg_average_grids_boundaries_task(
+ void *__restrict userdata_v,
+ const int adjacent_edge_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
+{
+ AverageGridsBoundariesData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ SubdivCCGAdjacentEdge *adjacent_edge =
+ &subdiv_ccg->adjacent_edges[adjacent_edge_index];
+ subdiv_ccg_average_grids_boundary(subdiv_ccg, key, adjacent_edge);
+}
+
+typedef struct AverageGridsCornerData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+} AverageGridsCornerData;
+
+static void subdiv_ccg_average_grids_corners(
+ SubdivCCG *subdiv_ccg,
+ CCGKey *key,
+ SubdivCCGAdjacentVertex *adjacent_vertex)
+{
+ const int num_adjacent_faces = adjacent_vertex->num_adjacent_faces;
+ if (num_adjacent_faces == 1) {
+ /* Nothing to average with. */
+ return;
+ }
+ /* Incrementall average result to elements of a first adjacent face.
+ * See comment to the boundary averaging.
+ */
+ for (int face_index = 1; face_index < num_adjacent_faces; face_index++) {
+ CCGElem *grid_element_0 =
+ adjacent_vertex->corner_elements[0];
+ CCGElem *grid_element_face_index =
+ adjacent_vertex->corner_elements[face_index];
+ average_grid_element(subdiv_ccg,
+ key,
+ grid_element_0,
+ grid_element_face_index);
+ }
+ /* Copy averaged value to all the other faces. */
+ for (int face_index = 1; face_index < num_adjacent_faces; face_index++) {
+ CCGElem *grid_element_0 =
+ adjacent_vertex->corner_elements[0];
+ CCGElem *grid_element_face_index =
+ adjacent_vertex->corner_elements[face_index];
+ copy_grid_element(subdiv_ccg,
+ key,
+ grid_element_face_index,
+ grid_element_0);
+ }
+}
+
+static void subdiv_ccg_average_grids_corners_task(
+ void *__restrict userdata_v,
+ const int adjacent_vertex_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
+{
+ AverageGridsCornerData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ SubdivCCGAdjacentVertex *adjacent_vertex =
+ &subdiv_ccg->adjacent_vertices[adjacent_vertex_index];
+ subdiv_ccg_average_grids_corners(subdiv_ccg, key, adjacent_vertex);
+}
+
+static void subdiv_ccg_average_all_boundaries_and_corners(
+ SubdivCCG *subdiv_ccg,
+ CCGKey *key)
+{
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ /* Average grids across coarse edges. */
+ AverageGridsBoundariesData boundaries_data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = key,
+ };
+ BLI_task_parallel_range(0, subdiv_ccg->num_adjacent_edges,
+ &boundaries_data,
+ subdiv_ccg_average_grids_boundaries_task,
+ &parallel_range_settings);
+ /* Average grids at coarse vertices. */
+ AverageGridsCornerData corner_data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = key,
+ };
+ BLI_task_parallel_range(0, subdiv_ccg->num_adjacent_vertices,
+ &corner_data,
+ subdiv_ccg_average_grids_corners_task,
+ &parallel_range_settings);
+}
+
+void BKE_subdiv_ccg_average_grids(SubdivCCG *subdiv_ccg)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ /* Average inner boundaries of grids (within one face), across faces
+ * from different face-corners.
+ */
+ AverageInnerGridsData inner_data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key,
+ };
+ BLI_task_parallel_range(0, subdiv_ccg->num_faces,
+ &inner_data,
+ subdiv_ccg_average_inner_grids_task,
+ &parallel_range_settings);
+ subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
+}
+
+typedef struct StitchFacesInnerGridsData {
+ SubdivCCG *subdiv_ccg;
+ CCGKey *key;
+ struct CCGFace **effected_ccg_faces;
+} StitchFacesInnerGridsData;
+
+static void subdiv_ccg_stitch_face_inner_grids_task(
+ void *__restrict userdata_v,
+ const int face_index,
+ const ParallelRangeTLS *__restrict UNUSED(tls_v))
+{
+ StitchFacesInnerGridsData *data = userdata_v;
+ SubdivCCG *subdiv_ccg = data->subdiv_ccg;
+ CCGKey *key = data->key;
+ struct CCGFace **effected_ccg_faces = data->effected_ccg_faces;
+ struct CCGFace *effected_ccg_face = effected_ccg_faces[face_index];
+ SubdivCCGFace *face = (SubdivCCGFace *)effected_ccg_face;
+ subdiv_ccg_average_inner_face_grids(subdiv_ccg, key, face);
+}
+
+void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG *subdiv_ccg,
+ struct CCGFace **effected_faces,
+ int num_effected_faces)
+{
+ CCGKey key;
+ BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
+ StitchFacesInnerGridsData data = {
+ .subdiv_ccg = subdiv_ccg,
+ .key = &key,
+ .effected_ccg_faces = effected_faces,
+ };
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ BLI_task_parallel_range(0, num_effected_faces,
+ &data,
+ subdiv_ccg_stitch_face_inner_grids_task,
+ &parallel_range_settings);
+ /* TODO(sergey): Only average elements which are adjacent to modified
+ * faces.
+ */
+ subdiv_ccg_average_all_boundaries_and_corners(subdiv_ccg, &key);
+}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg_mask.c b/source/blender/blenkernel/intern/subdiv_ccg_mask.c
new file mode 100644
index 00000000000..0da30fb1bf0
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_ccg_mask.c
@@ -0,0 +1,197 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_ccg_mask.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_ccg.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_subdiv.h"
+
+#include "MEM_guardedalloc.h"
+
+typedef struct PolyCornerIndex {
+ int poly_index;
+ int corner;
+} PolyCornerIndex;
+
+typedef struct GridPaintMaskData {
+ // int grid_size;
+ const MPoly *mpoly;
+ const GridPaintMask *grid_paint_mask;
+ /* Indexed by ptex face index, contains polygon/corner which corresponds
+ * to it.
+ *
+ * NOTE: For quad polygon this is an index of first corner only, since
+ * there we only have one ptex.
+ */
+ PolyCornerIndex *ptex_poly_corner;
+} GridPaintMaskData;
+
+static int mask_get_grid_and_coord(
+ SubdivCCGMask *mask_evaluator,
+ const int ptex_face_index, const float u, const float v,
+ const GridPaintMask **r_mask_grid,
+ float *grid_u, float *grid_v)
+{
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int start_grid_index = poly->loopstart + poly_corner->corner;
+ int corner = 0;
+ if (poly->totloop == 4) {
+ float corner_u, corner_v;
+ corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
+ *r_mask_grid =
+ &data->grid_paint_mask[start_grid_index + corner];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
+ }
+ else {
+ *r_mask_grid =
+ &data->grid_paint_mask[start_grid_index];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
+ }
+ return corner;
+}
+
+BLI_INLINE float read_mask_grid(const GridPaintMask *mask_grid,
+ const float grid_u, const float grid_v)
+{
+ if (mask_grid->data == NULL) {
+ return 0;
+ }
+ const int grid_size = BKE_subdiv_grid_size_from_level(mask_grid->level);
+ const int x = (grid_u * (grid_size - 1) + 0.5f);
+ const int y = (grid_v * (grid_size - 1) + 0.5f);
+ return mask_grid->data[y * grid_size + x];
+}
+
+static float eval_mask(SubdivCCGMask *mask_evaluator,
+ const int ptex_face_index,
+ const float u, const float v)
+{
+ const GridPaintMask *mask_grid;
+ float grid_u, grid_v;
+ mask_get_grid_and_coord(mask_evaluator,
+ ptex_face_index, u, v,
+ &mask_grid,
+ &grid_u, &grid_v);
+ return read_mask_grid(mask_grid, grid_u, grid_v);
+}
+
+static void free_mask_data(SubdivCCGMask *mask_evaluator)
+{
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ MEM_freeN(data->ptex_poly_corner);
+ MEM_freeN(data);
+}
+
+/* TODO(sergey): This seems to be generally used information, which almost
+ * worth adding to a subdiv itself, with possible cache of the value.
+ */
+static int count_num_ptex_faces(const Mesh *mesh)
+{
+ int num_ptex_faces = 0;
+ const MPoly *mpoly = mesh->mpoly;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
+ }
+ return num_ptex_faces;
+}
+
+static void displacement_data_init_mapping(SubdivCCGMask *mask_evaluator,
+ const Mesh *mesh)
+{
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ const MPoly *mpoly = mesh->mpoly;
+ const int num_ptex_faces = count_num_ptex_faces(mesh);
+ /* Allocate memory. */
+ data->ptex_poly_corner = MEM_malloc_arrayN(num_ptex_faces,
+ sizeof(*data->ptex_poly_corner),
+ "ptex poly corner");
+ /* Fill in offsets. */
+ int ptex_face_index = 0;
+ PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ if (poly->totloop == 4) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = 0;
+ ptex_face_index++;
+ }
+ else {
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = corner;
+ ptex_face_index++;
+ }
+ }
+ }
+}
+
+static void displacement_init_data(SubdivCCGMask *mask_evaluator,
+ const Mesh *mesh)
+{
+ GridPaintMaskData *data = mask_evaluator->user_data;
+ data->mpoly = mesh->mpoly;
+ data->grid_paint_mask =
+ CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ displacement_data_init_mapping(mask_evaluator, mesh);
+}
+
+static void displacement_init_functions(SubdivCCGMask *mask_evaluator)
+{
+ mask_evaluator->eval_mask = eval_mask;
+ mask_evaluator->free = free_mask_data;
+}
+
+bool BKE_subdiv_ccg_mask_init_from_paint(
+ SubdivCCGMask *mask_evaluator,
+ const struct Mesh *mesh)
+{
+ GridPaintMask *grid_paint_mask =
+ CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK);
+ if (grid_paint_mask == NULL) {
+ return false;
+ }
+ /* Allocate all required memory. */
+ mask_evaluator->user_data = MEM_callocN(sizeof(GridPaintMaskData),
+ "mask from grid data");
+ displacement_init_data(mask_evaluator, mesh);
+ displacement_init_functions(mask_evaluator);
+ return true;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_converter.c b/source/blender/blenkernel/intern/subdiv_converter.c
new file mode 100644
index 00000000000..b3eab1565d7
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_converter.c
@@ -0,0 +1,77 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_converter.c
+ * \ingroup bke
+ */
+
+#include "subdiv_converter.h"
+
+#include "BLI_utildefines.h"
+
+#include "opensubdiv_converter_capi.h"
+
+void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter)
+{
+ if (converter->freeUserData) {
+ converter->freeUserData(converter);
+ }
+}
+
+int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
+ const SubdivSettings *settings)
+{
+ switch (settings->vtx_boundary_interpolation) {
+ case SUBDIV_VTX_BOUNDARY_NONE:
+ return OSD_VTX_BOUNDARY_NONE;
+ case SUBDIV_VTX_BOUNDARY_EDGE_ONLY:
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
+ case SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER:
+ return OSD_VTX_BOUNDARY_EDGE_AND_CORNER;
+ }
+ BLI_assert(!"Unknown vtx boundary interpolation");
+ return OSD_VTX_BOUNDARY_EDGE_ONLY;
+}
+
+/*OpenSubdiv_FVarLinearInterpolation*/ int
+BKE_subdiv_converter_fvar_linear_from_settings(const SubdivSettings *settings)
+{
+ switch (settings->fvar_linear_interpolation) {
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE:
+ return OSD_FVAR_LINEAR_INTERPOLATION_NONE;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY:
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS:
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS1;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_JUNCTIONS_AND_CONCAVE:
+ return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS2;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_BOUNDARIES:
+ return OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES;
+ case SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL:
+ return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
+ }
+ BLI_assert(!"Unknown fvar linear interpolation");
+ return OSD_FVAR_LINEAR_INTERPOLATION_NONE;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_converter.h b/source/blender/blenkernel/intern/subdiv_converter.h
new file mode 100644
index 00000000000..17172bc29f7
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_converter.h
@@ -0,0 +1,67 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __SUBDIV_CONVERTER_H__
+#define __SUBDIV_CONVERTER_H__
+
+/** \file blender/blenkernel/intern/subdiv_converter.h
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+/* NOTE: Was initially used to get proper enumerator types, but this makes
+ * it tricky to compile without OpenSubdiv.
+ */
+/* #include "opensubdiv_converter_capi.h" */
+
+struct Mesh;
+struct OpenSubdiv_Converter;
+struct SubdivSettings;
+
+void BKE_subdiv_converter_init_for_mesh(struct OpenSubdiv_Converter *converter,
+ const struct SubdivSettings *settings,
+ const struct Mesh *mesh);
+
+/* NOTE: Frees converter data, but not converter itself. This means, that if
+ * converter was allocated on heap, it is up to the user to free that memory.
+ */
+void BKE_subdiv_converter_free(struct OpenSubdiv_Converter *converter);
+
+/* ============================ INTERNAL HELPERS ============================ */
+
+/* TODO(sergey): Find a way to make it OpenSubdiv_VtxBoundaryInterpolation,
+ * without breaking compilation without OpenSubdiv.
+ */
+int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
+ const SubdivSettings *settings);
+
+/* TODO(sergey): Find a way to make it OpenSubdiv_FVarLinearInterpolation,
+ * without breaking compilation without OpenSubdiv.
+ */
+int BKE_subdiv_converter_fvar_linear_from_settings(
+ const SubdivSettings *settings);
+
+#endif /* __SUBDIV_CONVERTER_H__ */
diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
new file mode 100644
index 00000000000..5941de682f4
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -0,0 +1,410 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_converter_mesh.c
+ * \ingroup bke
+ */
+
+#include "subdiv_converter.h"
+
+#include <string.h>
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_subdiv.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "opensubdiv_capi.h"
+#include "opensubdiv_converter_capi.h"
+
+typedef struct ConverterStorage {
+ SubdivSettings settings;
+ const Mesh *mesh;
+ /* Indexed by loop index, value denotes index of face-varying vertex
+ * which corresponds to the UV coordinate.
+ */
+ int *loop_uv_indices;
+ int num_uv_coordinates;
+ /* Indexed by coarse mesh elements, gives index of corresponding element
+ * with ignoring all non-manifold entities.
+ *
+ * NOTE: This isn't strictly speaking manifold, this is more like non-loose
+ * geometry index. As in, index of element as if there were no loose edges
+ * or vertices in the mesh.
+ */
+ int *manifold_vertex_index;
+ /* Indexed by vertex index from mesh, corresponds to whether this vertex has
+ * infinite sharpness due to non-manifol topology.
+ */
+ BLI_bitmap *infinite_sharp_vertices_map;
+ /* Reverse mapping to above. */
+ int *manifold_vertex_index_reverse;
+ int *manifold_edge_index_reverse;
+ /* Number of non-loose elements. */
+ int num_manifold_vertices;
+ int num_manifold_edges;
+} ConverterStorage;
+
+static OpenSubdiv_SchemeType get_scheme_type(
+ const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ if (storage->settings.is_simple) {
+ return OSD_SCHEME_BILINEAR;
+ }
+ else {
+ return OSD_SCHEME_CATMARK;
+ }
+}
+
+static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation(
+ const struct OpenSubdiv_Converter *converter) {
+ ConverterStorage *storage = converter->user_data;
+ return BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(
+ &storage->settings);
+}
+
+static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(
+ const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return BKE_subdiv_converter_fvar_linear_from_settings(&storage->settings);
+}
+
+static bool specifies_full_topology(
+ const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return false;
+}
+
+static int get_num_faces(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->mesh->totpoly;
+}
+
+static int get_num_edges(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->num_manifold_edges;
+}
+
+static int get_num_vertices(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->num_manifold_vertices;
+}
+
+static int get_num_face_vertices(const OpenSubdiv_Converter *converter,
+ int manifold_face_index)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->mesh->mpoly[manifold_face_index].totloop;
+}
+
+static void get_face_vertices(const OpenSubdiv_Converter *converter,
+ int manifold_face_index,
+ int *manifold_face_vertices)
+{
+ ConverterStorage *storage = converter->user_data;
+ const MPoly *poly = &storage->mesh->mpoly[manifold_face_index];
+ const MLoop *mloop = storage->mesh->mloop;
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ manifold_face_vertices[corner] = storage->manifold_vertex_index[
+ mloop[poly->loopstart + corner].v];
+ }
+}
+
+static void get_edge_vertices(const OpenSubdiv_Converter *converter,
+ int manifold_edge_index,
+ int *manifold_edge_vertices)
+{
+ ConverterStorage *storage = converter->user_data;
+ const int edge_index =
+ storage->manifold_edge_index_reverse[manifold_edge_index];
+ const MEdge *edge = &storage->mesh->medge[edge_index];
+ manifold_edge_vertices[0] = storage->manifold_vertex_index[edge->v1];
+ manifold_edge_vertices[1] = storage->manifold_vertex_index[edge->v2];
+}
+
+static float get_edge_sharpness(const OpenSubdiv_Converter *converter,
+ int manifold_edge_index)
+{
+ ConverterStorage *storage = converter->user_data;
+ const int edge_index =
+ storage->manifold_edge_index_reverse[manifold_edge_index];
+ const MEdge *medge = storage->mesh->medge;
+ const float edge_crease = (float)medge[edge_index].crease / 255.0f;
+ return edge_crease * edge_crease * 10.0f;
+}
+
+
+static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
+ int manifold_vertex_index)
+{
+ ConverterStorage *storage = converter->user_data;
+ const int vertex_index =
+ storage->manifold_vertex_index_reverse[manifold_vertex_index];
+ return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map,
+ vertex_index);
+}
+
+static float get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
+ int UNUSED(manifold_vertex_index))
+{
+ return 0.0f;
+}
+
+static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ const Mesh *mesh = storage->mesh;
+ return CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
+}
+
+static void precalc_uv_layer(const OpenSubdiv_Converter *converter,
+ const int layer_index)
+{
+ ConverterStorage *storage = converter->user_data;
+ const Mesh *mesh = storage->mesh;
+ const MPoly *mpoly = mesh->mpoly;
+ const MLoop *mloop = mesh->mloop;
+ const MLoopUV *mloopuv = CustomData_get_layer_n(
+ &mesh->ldata, CD_MLOOPUV, layer_index);
+ const int num_poly = mesh->totpoly;
+ const int num_vert = mesh->totvert;
+ const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
+ /* Initialize memory required for the operations. */
+ if (storage->loop_uv_indices == NULL) {
+ storage->loop_uv_indices = MEM_malloc_arrayN(
+ mesh->totloop, sizeof(int), "loop uv vertex index");
+ }
+ UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(
+ mpoly, mloop, mloopuv,
+ num_poly, num_vert,
+ limit,
+ false, true);
+ /* NOTE: First UV vertex is supposed to be always marked as separate. */
+ storage->num_uv_coordinates = -1;
+ for (int vertex_index = 0; vertex_index < num_vert; ++vertex_index) {
+ const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map,
+ vertex_index);
+ while (uv_vert != NULL) {
+ if (uv_vert->separate) {
+ storage->num_uv_coordinates++;
+ }
+ const MPoly *mp = &mpoly[uv_vert->poly_index];
+ const int global_loop_index = mp->loopstart +
+ uv_vert->loop_of_poly_index;
+ storage->loop_uv_indices[global_loop_index] =
+ storage->num_uv_coordinates;
+ uv_vert = uv_vert->next;
+ }
+ }
+ /* So far this value was used as a 0-based index, actual number of UV
+ * vertices is 1 more.
+ */
+ storage->num_uv_coordinates += 1;
+ BKE_mesh_uv_vert_map_free(uv_vert_map);
+}
+
+static void finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter))
+{
+}
+
+static int get_num_uvs(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *storage = converter->user_data;
+ return storage->num_uv_coordinates;
+}
+
+static int get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
+ const int face_index,
+ const int corner)
+{
+ ConverterStorage *storage = converter->user_data;
+ const MPoly *mp = &storage->mesh->mpoly[face_index];
+ return storage->loop_uv_indices[mp->loopstart + corner];
+}
+
+static void free_user_data(const OpenSubdiv_Converter *converter)
+{
+ ConverterStorage *user_data = converter->user_data;
+ MEM_SAFE_FREE(user_data->loop_uv_indices);
+ MEM_freeN(user_data->manifold_vertex_index);
+ MEM_freeN(user_data->infinite_sharp_vertices_map);
+ MEM_freeN(user_data->manifold_vertex_index_reverse);
+ MEM_freeN(user_data->manifold_edge_index_reverse);
+ MEM_freeN(user_data);
+}
+
+static void init_functions(OpenSubdiv_Converter *converter)
+{
+ converter->getSchemeType = get_scheme_type;
+ converter->getVtxBoundaryInterpolation = get_vtx_boundary_interpolation;
+ converter->getFVarLinearInterpolation = get_fvar_linear_interpolation;
+ converter->specifiesFullTopology = specifies_full_topology;
+
+ converter->getNumFaces = get_num_faces;
+ converter->getNumEdges = get_num_edges;
+ converter->getNumVertices = get_num_vertices;
+
+ converter->getNumFaceVertices = get_num_face_vertices;
+ converter->getFaceVertices = get_face_vertices;
+ converter->getFaceEdges = NULL;
+
+ converter->getEdgeVertices = get_edge_vertices;
+ converter->getNumEdgeFaces = NULL;
+ converter->getEdgeFaces = NULL;
+ converter->getEdgeSharpness = get_edge_sharpness;
+
+ converter->getNumVertexEdges = NULL;
+ converter->getVertexEdges = NULL;
+ converter->getNumVertexFaces = NULL;
+ converter->getVertexFaces = NULL;
+ converter->isInfiniteSharpVertex = is_infinite_sharp_vertex;
+ converter->getVertexSharpness = get_vertex_sharpness;
+
+ converter->getNumUVLayers = get_num_uv_layers;
+ converter->precalcUVLayer = precalc_uv_layer;
+ converter->finishUVLayer = finish_uv_layer;
+ converter->getNumUVCoordinates = get_num_uvs;
+ converter->getFaceCornerUVIndex = get_face_corner_uv_index;
+
+ converter->freeUserData = free_user_data;
+}
+
+static void initialize_manifold_index_array(const BLI_bitmap *used_map,
+ const int num_elements,
+ int **indices_r,
+ int **indices_reverse_r,
+ int *num_manifold_elements_r)
+{
+ int *indices = NULL;
+ if (indices_r != NULL) {
+ indices = MEM_malloc_arrayN(
+ num_elements, sizeof(int), "manifold indices");
+ }
+ int *indices_reverse = NULL;
+ if (indices_reverse_r != NULL) {
+ indices_reverse = MEM_malloc_arrayN(
+ num_elements, sizeof(int), "manifold indices reverse");
+ }
+ int offset = 0;
+ for (int i = 0; i < num_elements; i++) {
+ if (BLI_BITMAP_TEST_BOOL(used_map, i)) {
+ if (indices != NULL) {
+ indices[i] = i - offset;
+ }
+ if (indices_reverse != NULL) {
+ indices_reverse[i - offset] = i;
+ }
+ }
+ else {
+ if (indices != NULL) {
+ indices[i] = -1;
+ }
+ offset++;
+ }
+ }
+ if (indices_r != NULL) {
+ *indices_r = indices;
+ }
+ if (indices_reverse_r != NULL) {
+ *indices_reverse_r = indices_reverse;
+ }
+ *num_manifold_elements_r = num_elements - offset;
+}
+
+static void initialize_manifold_indices(ConverterStorage *storage)
+{
+ const Mesh *mesh = storage->mesh;
+ const MEdge *medge = mesh->medge;
+ const MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+ /* Set bits of elements which are not loose. */
+ BLI_bitmap *vert_used_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map");
+ BLI_bitmap *edge_used_map = BLI_BITMAP_NEW(mesh->totedge, "edge used map");
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ const MLoop *loop = &mloop[poly->loopstart + corner];
+ BLI_BITMAP_ENABLE(vert_used_map, loop->v);
+ BLI_BITMAP_ENABLE(edge_used_map, loop->e);
+ }
+ }
+ initialize_manifold_index_array(vert_used_map,
+ mesh->totvert,
+ &storage->manifold_vertex_index,
+ &storage->manifold_vertex_index_reverse,
+ &storage->num_manifold_vertices);
+ initialize_manifold_index_array(edge_used_map,
+ mesh->totedge,
+ NULL,
+ &storage->manifold_edge_index_reverse,
+ &storage->num_manifold_edges);
+ /* Initialize infinite sharp mapping. */
+ storage->infinite_sharp_vertices_map =
+ BLI_BITMAP_NEW(mesh->totvert, "vert used map");
+ for (int edge_index = 0; edge_index < mesh->totedge; edge_index++) {
+ if (!BLI_BITMAP_TEST_BOOL(edge_used_map, edge_index)) {
+ const MEdge *edge = &medge[edge_index];
+ BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v1);
+ BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge->v2);
+ }
+ }
+ /* Free working variables. */
+ MEM_freeN(vert_used_map);
+ MEM_freeN(edge_used_map);
+}
+
+static void init_user_data(OpenSubdiv_Converter *converter,
+ const SubdivSettings *settings,
+ const Mesh *mesh)
+{
+ ConverterStorage *user_data =
+ MEM_mallocN(sizeof(ConverterStorage), __func__);
+ user_data->settings = *settings;
+ user_data->mesh = mesh;
+ user_data->loop_uv_indices = NULL;
+ initialize_manifold_indices(user_data);
+ converter->user_data = user_data;
+}
+
+void BKE_subdiv_converter_init_for_mesh(struct OpenSubdiv_Converter *converter,
+ const SubdivSettings *settings,
+ const Mesh *mesh)
+{
+ init_functions(converter);
+ init_user_data(converter, settings, mesh);
+}
diff --git a/source/blender/blenkernel/intern/subdiv_displacement.c b/source/blender/blenkernel/intern/subdiv_displacement.c
new file mode 100644
index 00000000000..a6af6f45e59
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_displacement.c
@@ -0,0 +1,46 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_displacement.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+void BKE_subdiv_displacement_detach(Subdiv *subdiv)
+{
+ if (subdiv->displacement_evaluator == NULL) {
+ return;
+ }
+ if (subdiv->displacement_evaluator->free != NULL) {
+ subdiv->displacement_evaluator->free(subdiv->displacement_evaluator);
+ }
+ MEM_freeN(subdiv->displacement_evaluator);
+ subdiv->displacement_evaluator = NULL;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_displacement_multires.c b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
new file mode 100644
index 00000000000..5744ac3ca0d
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.c
@@ -0,0 +1,358 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_displacement_multires.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_multires.h"
+
+#include "MEM_guardedalloc.h"
+
+typedef struct PolyCornerIndex {
+ int poly_index;
+ int corner;
+} PolyCornerIndex;
+
+typedef struct MultiresDisplacementData {
+ int grid_size;
+ const MPoly *mpoly;
+ const MDisps *mdisps;
+ /* Indexed by ptex face index, contains polygon/corner which corresponds
+ * to it.
+ *
+ * NOTE: For quad polygon this is an index of first corner only, since
+ * there we only have one ptex.
+ */
+ PolyCornerIndex *ptex_poly_corner;
+} MultiresDisplacementData;
+
+/* Denotes which grid to use to average value of the displacement read from the
+ * grid which corresponds to the ptex face.
+ */
+typedef enum eAverageWith {
+ AVERAGE_WITH_NONE,
+ AVERAGE_WITH_ALL,
+ AVERAGE_WITH_PREV,
+ AVERAGE_WITH_NEXT,
+} eAverageWith;
+
+static int displacement_get_grid_and_coord(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const float u, const float v,
+ const MDisps **r_displacement_grid,
+ float *grid_u, float *grid_v)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int start_grid_index = poly->loopstart + poly_corner->corner;
+ int corner = 0;
+ if (poly->totloop == 4) {
+ float corner_u, corner_v;
+ corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
+ *r_displacement_grid = &data->mdisps[start_grid_index + corner];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
+ }
+ else {
+ *r_displacement_grid = &data->mdisps[start_grid_index];
+ BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
+ }
+ return corner;
+}
+
+static const MDisps *displacement_get_next_grid(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int effective_corner = (poly->totloop == 4) ? corner
+ : poly_corner->corner;
+ const int next_corner = (effective_corner + 1) % poly->totloop;
+ return &data->mdisps[poly->loopstart + next_corner];
+}
+
+static const MDisps *displacement_get_prev_grid(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ const int effective_corner = (poly->totloop == 4) ? corner
+ : poly_corner->corner;
+ const int prev_corner =
+ (effective_corner - 1 + poly->totloop) % poly->totloop;
+ return &data->mdisps[poly->loopstart + prev_corner];
+}
+
+BLI_INLINE eAverageWith read_displacement_grid(
+ const MDisps *displacement_grid,
+ const int grid_size,
+ const float grid_u, const float grid_v,
+ float r_tangent_D[3])
+{
+ if (displacement_grid->disps == NULL) {
+ zero_v3(r_tangent_D);
+ return AVERAGE_WITH_NONE;
+ }
+ const int x = (grid_u * (grid_size - 1) + 0.5f);
+ const int y = (grid_v * (grid_size - 1) + 0.5f);
+ copy_v3_v3(r_tangent_D, displacement_grid->disps[y * grid_size + x]);
+ if (x == 0 && y == 0) {
+ return AVERAGE_WITH_ALL;
+ }
+ else if (x == 0) {
+ return AVERAGE_WITH_PREV;
+ }
+ else if (y == 0) {
+ return AVERAGE_WITH_NEXT;
+ }
+ return AVERAGE_WITH_NONE;
+}
+
+static void average_with_all(
+ SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ const float UNUSED(grid_u), const float UNUSED(grid_v),
+ float r_tangent_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const PolyCornerIndex *poly_corner =
+ &data->ptex_poly_corner[ptex_face_index];
+ const MPoly *poly = &data->mpoly[poly_corner->poly_index];
+ for (int current_corner = 0;
+ current_corner < poly->totloop;
+ current_corner++)
+ {
+ if (current_corner == corner) {
+ continue;
+ }
+ const MDisps *displacement_grid =
+ &data->mdisps[poly->loopstart + current_corner];
+ const float *current_tangent_D = displacement_grid->disps[0];
+ r_tangent_D[2] += current_tangent_D[2];
+ }
+ r_tangent_D[2] /= (float)poly->totloop;
+}
+
+static void average_with_next(SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ const float grid_u, const float UNUSED(grid_v),
+ float r_tangent_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const int grid_size = data->grid_size;
+ const MDisps *next_displacement_grid = displacement_get_next_grid(
+ displacement, ptex_face_index, corner);
+ float next_tangent_D[3];
+ read_displacement_grid(next_displacement_grid, grid_size,
+ 0.0f, grid_u,
+ next_tangent_D);
+ r_tangent_D[2] += next_tangent_D[2];
+ r_tangent_D[2] *= 0.5f;
+}
+
+static void average_with_prev(SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ const float UNUSED(grid_u), const float grid_v,
+ float r_tangent_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const int grid_size = data->grid_size;
+ const MDisps *prev_displacement_grid = displacement_get_prev_grid(
+ displacement, ptex_face_index, corner);
+ float prev_tangent_D[3];
+ read_displacement_grid(prev_displacement_grid, grid_size,
+ grid_v, 0.0f,
+ prev_tangent_D);
+ r_tangent_D[2] += prev_tangent_D[2];
+ r_tangent_D[2] *= 0.5f;
+}
+
+static void average_displacement(SubdivDisplacement *displacement,
+ const int ptex_face_index, const int corner,
+ eAverageWith average_with,
+ const float grid_u, const float grid_v,
+ float r_tangent_D[3])
+{
+ switch (average_with) {
+ case AVERAGE_WITH_ALL:
+ average_with_all(displacement,
+ ptex_face_index, corner,
+ grid_u, grid_v,
+ r_tangent_D);
+ break;
+ case AVERAGE_WITH_PREV:
+ average_with_prev(displacement,
+ ptex_face_index, corner,
+ grid_u, grid_v,
+ r_tangent_D);
+ break;
+ case AVERAGE_WITH_NEXT:
+ average_with_next(displacement,
+ ptex_face_index, corner,
+ grid_u, grid_v,
+ r_tangent_D);
+ break;
+ case AVERAGE_WITH_NONE:
+ break;
+ }
+}
+
+static void eval_displacement(SubdivDisplacement *displacement,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3])
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const int grid_size = data->grid_size;
+ /* Get displacement in tangent space. */
+ const MDisps *displacement_grid;
+ float grid_u, grid_v;
+ int corner = displacement_get_grid_and_coord(displacement,
+ ptex_face_index, u, v,
+ &displacement_grid,
+ &grid_u, &grid_v);
+ /* Read displacement from the current displacement grid and see if any
+ * averaging is needed.
+ */
+ float tangent_D[3];
+ eAverageWith average_with =
+ read_displacement_grid(displacement_grid, grid_size,
+ grid_u, grid_v,
+ tangent_D);
+ average_displacement(displacement,
+ ptex_face_index, corner,
+ average_with, grid_u, grid_v,
+ tangent_D);
+ /* Convert it to the object space. */
+ float tangent_matrix[3][3];
+ BKE_multires_construct_tangent_matrix(tangent_matrix, dPdu, dPdv, corner);
+ mul_v3_m3v3(r_D, tangent_matrix, tangent_D);
+}
+
+static void free_displacement(SubdivDisplacement *displacement)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ MEM_freeN(data->ptex_poly_corner);
+ MEM_freeN(data);
+}
+
+/* TODO(sergey): This seems to be generally used information, which almost
+ * worth adding to a subdiv itself, with possible cache of the value.
+ */
+static int count_num_ptex_faces(const Mesh *mesh)
+{
+ int num_ptex_faces = 0;
+ const MPoly *mpoly = mesh->mpoly;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ num_ptex_faces += (poly->totloop == 4) ? 1 : poly->totloop;
+ }
+ return num_ptex_faces;
+}
+
+static void displacement_data_init_mapping(SubdivDisplacement *displacement,
+ const Mesh *mesh)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ const MPoly *mpoly = mesh->mpoly;
+ const int num_ptex_faces = count_num_ptex_faces(mesh);
+ /* Allocate memory. */
+ data->ptex_poly_corner = MEM_malloc_arrayN(num_ptex_faces,
+ sizeof(*data->ptex_poly_corner),
+ "ptex poly corner");
+ /* Fill in offsets. */
+ int ptex_face_index = 0;
+ PolyCornerIndex *ptex_poly_corner = data->ptex_poly_corner;
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ if (poly->totloop == 4) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = 0;
+ ptex_face_index++;
+ }
+ else {
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ ptex_poly_corner[ptex_face_index].poly_index = poly_index;
+ ptex_poly_corner[ptex_face_index].corner = corner;
+ ptex_face_index++;
+ }
+ }
+ }
+}
+
+static void displacement_init_data(SubdivDisplacement *displacement,
+ const Mesh *mesh,
+ const MultiresModifierData *mmd)
+{
+ MultiresDisplacementData *data = displacement->user_data;
+ data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl);
+ data->mpoly = mesh->mpoly;
+ data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS);
+ displacement_data_init_mapping(displacement, mesh);
+}
+
+static void displacement_init_functions(SubdivDisplacement *displacement)
+{
+ displacement->eval_displacement = eval_displacement;
+ displacement->free = free_displacement;
+}
+
+void BKE_subdiv_displacement_attach_from_multires(
+ Subdiv *subdiv,
+ const Mesh *mesh,
+ const MultiresModifierData *mmd)
+{
+ /* Make sure we don't have previously assigned displacement. */
+ BKE_subdiv_displacement_detach(subdiv);
+ /* Allocate all required memory. */
+ SubdivDisplacement *displacement = MEM_callocN(sizeof(SubdivDisplacement),
+ "multires displacement");
+ displacement->user_data = MEM_callocN(sizeof(MultiresDisplacementData),
+ "multires displacement data");
+ displacement_init_data(displacement, mesh, mmd);
+ displacement_init_functions(displacement);
+ /* Finish. */
+ subdiv->displacement_evaluator = displacement;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
new file mode 100644
index 00000000000..f4a9e1a95fd
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -0,0 +1,394 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_eval.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_eval.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_customdata.h"
+#include "BKE_subdiv.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
+
+bool BKE_subdiv_eval_begin(Subdiv *subdiv)
+{
+ if (subdiv->topology_refiner == NULL) {
+ /* Happens on input mesh with just loose geometry,
+ * or when OpenSubdiv is disabled
+ */
+ return false;
+ }
+ else if (subdiv->evaluator == NULL) {
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
+ subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(
+ subdiv->topology_refiner);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
+ if (subdiv->evaluator == NULL) {
+ return false;
+ }
+ }
+ else {
+ /* TODO(sergey): Check for topology change. */
+ }
+ return true;
+}
+
+static void set_coarse_positions(Subdiv *subdiv, const Mesh *mesh)
+{
+ const MVert *mvert = mesh->mvert;
+ const MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+ /* Mark vertices which needs new coordinates. */
+ /* TODO(sergey): This is annoying to calculate this on every update,
+ * maybe it's better to cache this mapping. Or make it possible to have
+ * OpenSubdiv's vertices match mesh ones?
+ */
+ BLI_bitmap *vertex_used_map =
+ BLI_BITMAP_NEW(mesh->totvert, "vert used map");
+ for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
+ const MPoly *poly = &mpoly[poly_index];
+ for (int corner = 0; corner < poly->totloop; corner++) {
+ const MLoop *loop = &mloop[poly->loopstart + corner];
+ BLI_BITMAP_ENABLE(vertex_used_map, loop->v);
+ }
+ }
+ for (int vertex_index = 0, manifold_veretx_index = 0;
+ vertex_index < mesh->totvert;
+ vertex_index++)
+ {
+ if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
+ continue;
+ }
+ const MVert *vertex = &mvert[vertex_index];
+ subdiv->evaluator->setCoarsePositions(
+ subdiv->evaluator,
+ vertex->co,
+ manifold_veretx_index, 1);
+ manifold_veretx_index++;
+ }
+ MEM_freeN(vertex_used_map);
+}
+
+static void set_face_varying_data_from_uv(Subdiv *subdiv,
+ const MLoopUV *mloopuv,
+ const int layer_index)
+{
+ OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+ const int num_faces = topology_refiner->getNumFaces(topology_refiner);
+ const MLoopUV *mluv = mloopuv;
+ /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
+ * loops of a face, need to watch for that, to prevent wrong UVs assigned.
+ */
+ for (int face_index = 0; face_index < num_faces; ++face_index) {
+ const int num_face_vertices = topology_refiner->getNumFaceVertices(
+ topology_refiner, face_index);
+ const int *uv_indicies = topology_refiner->getFaceFVarValueIndices(
+ topology_refiner, face_index, layer_index);
+ for (int vertex_index = 0;
+ vertex_index < num_face_vertices;
+ vertex_index++, mluv++)
+ {
+ evaluator->setFaceVaryingData(evaluator,
+ layer_index,
+ mluv->uv,
+ uv_indicies[vertex_index],
+ 1);
+ }
+ }
+}
+
+bool BKE_subdiv_eval_update_from_mesh(Subdiv *subdiv, const Mesh *mesh)
+{
+ if (!BKE_subdiv_eval_begin(subdiv)) {
+ return false;
+ }
+ if (subdiv->evaluator == NULL) {
+ /* NOTE: This situation is supposed to be handled by begin(). */
+ BLI_assert(!"Is not supposed to happen");
+ return false;
+ }
+ /* Set coordinates of base mesh vertices. */
+ set_coarse_positions(subdiv, mesh);
+ /* Set face-varyign data to UV maps. */
+ const int num_uv_layers =
+ CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
+ for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
+ const MLoopUV *mloopuv = CustomData_get_layer_n(
+ &mesh->ldata, CD_MLOOPUV, layer_index);
+ set_face_varying_data_from_uv(subdiv, mloopuv, layer_index);
+ }
+ /* Update evaluator to the new coarse geometry. */
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
+ subdiv->evaluator->refine(subdiv->evaluator);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
+ return true;
+}
+
+/* ========================== Single point queries ========================== */
+
+void BKE_subdiv_eval_limit_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3])
+{
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
+ ptex_face_index,
+ u, v,
+ r_P, NULL, NULL);
+}
+
+void BKE_subdiv_eval_limit_point_and_derivatives(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], float r_dPdu[3], float r_dPdv[3])
+{
+ subdiv->evaluator->evaluateLimit(subdiv->evaluator,
+ ptex_face_index,
+ u, v,
+ r_P, r_dPdu, r_dPdv);
+}
+
+void BKE_subdiv_eval_limit_point_and_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], float r_N[3])
+{
+ float dPdu[3], dPdv[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(subdiv,
+ ptex_face_index,
+ u, v,
+ r_P, dPdu, dPdv);
+ cross_v3_v3v3(r_N, dPdu, dPdv);
+ normalize_v3(r_N);
+}
+
+void BKE_subdiv_eval_limit_point_and_short_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], short r_N[3])
+{
+ float N_float[3];
+ BKE_subdiv_eval_limit_point_and_normal(subdiv,
+ ptex_face_index,
+ u, v,
+ r_P, N_float);
+ normal_float_to_short_v3(r_N, N_float);
+}
+
+void BKE_subdiv_eval_face_varying(
+ Subdiv *subdiv,
+ const int face_varying_channel,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_face_varying[2])
+{
+ subdiv->evaluator->evaluateFaceVarying(subdiv->evaluator,
+ face_varying_channel,
+ ptex_face_index,
+ u, v,
+ r_face_varying);
+}
+
+void BKE_subdiv_eval_displacement(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ const float dPdu[3], const float dPdv[3],
+ float r_D[3])
+{
+ if (subdiv->displacement_evaluator == NULL) {
+ zero_v3(r_D);
+ return;
+ }
+ subdiv->displacement_evaluator->eval_displacement(
+ subdiv->displacement_evaluator,
+ ptex_face_index,
+ u, v,
+ dPdu, dPdv,
+ r_D);
+}
+
+void BKE_subdiv_eval_final_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3])
+{
+ if (subdiv->displacement_evaluator) {
+ float dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
+ BKE_subdiv_eval_displacement(subdiv,
+ ptex_face_index, u, v,
+ dPdu, dPdv,
+ D);
+ add_v3_v3(r_P, D);
+ }
+ else {
+ BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
+ }
+}
+
+/* =================== Patch queries at given resolution =================== */
+
+/* Move buffer forward by a given number of bytes. */
+static void buffer_apply_offset(void **buffer, const int offset)
+{
+ *buffer = ((unsigned char *)*buffer) + offset;
+}
+
+/* Write given number of floats to the beginning of given buffer. */
+static void buffer_write_float_value(void **buffer,
+ const float *values_buffer, int num_values)
+{
+ memcpy(*buffer, values_buffer, sizeof(float) * num_values);
+}
+
+/* Similar to above, just operates with short values. */
+static void buffer_write_short_value(void **buffer,
+ const short *values_buffer, int num_values)
+{
+ memcpy(*buffer, values_buffer, sizeof(short) * num_values);
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *buffer, const int offset, const int stride)
+{
+ buffer_apply_offset(&buffer, offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ BKE_subdiv_eval_limit_point(subdiv,
+ ptex_face_index,
+ u, v,
+ buffer);
+ buffer_apply_offset(&buffer, stride);
+ }
+ }
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point_and_derivatives(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *du_buffer, const int du_offset, const int du_stride,
+ void *dv_buffer, const int dv_offset, const int dv_stride)
+{
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&du_buffer, du_offset);
+ buffer_apply_offset(&dv_buffer, dv_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ point_buffer, du_buffer, dv_buffer);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&du_buffer, du_stride);
+ buffer_apply_offset(&dv_buffer, dv_stride);
+ }
+ }
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride)
+{
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&normal_buffer, normal_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ float normal[3];
+ BKE_subdiv_eval_limit_point_and_normal(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ point_buffer, normal);
+ buffer_write_float_value(&normal_buffer, normal, 3);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&normal_buffer, normal_stride);
+ }
+ }
+}
+
+void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const int resolution,
+ void *point_buffer, const int point_offset, const int point_stride,
+ void *normal_buffer, const int normal_offset, const int normal_stride)
+{
+ buffer_apply_offset(&point_buffer, point_offset);
+ buffer_apply_offset(&normal_buffer, normal_offset);
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ for (int y = 0; y < resolution; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 0; x < resolution; x++) {
+ const float u = x * inv_resolution_1;
+ short normal[3];
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv,
+ ptex_face_index,
+ u, v,
+ point_buffer, normal);
+ buffer_write_short_value(&normal_buffer, normal, 3);
+ buffer_apply_offset(&point_buffer, point_stride);
+ buffer_apply_offset(&normal_buffer, normal_stride);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c
new file mode 100644
index 00000000000..511536c31b5
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_foreach.c
@@ -0,0 +1,2038 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_foreach.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_foreach.h"
+
+#include "atomic_ops.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_bitmap.h"
+#include "BLI_math_vector.h"
+#include "BLI_task.h"
+
+#include "BKE_mesh.h"
+#include "BKE_key.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_mesh.h"
+
+#include "MEM_guardedalloc.h"
+
+/* =============================================================================
+ * General helpers.
+ */
+
+/* Number of ptex faces for a given polygon. */
+BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly)
+{
+ return (poly->totloop == 4) ? 1 : poly->totloop;
+}
+
+BLI_INLINE int num_edges_per_ptex_face_get(const int resolution)
+{
+ return 2 * (resolution - 1) * resolution;
+}
+
+BLI_INLINE int num_inner_edges_per_ptex_face_get(const int resolution)
+{
+ if (resolution < 2) {
+ return 0;
+ }
+ return (resolution - 2) * resolution +
+ (resolution - 1) * (resolution - 1);
+}
+
+/* Number of subdivision polygons per ptex face. */
+BLI_INLINE int num_polys_per_ptex_get(const int resolution)
+{
+ return (resolution - 1) * (resolution - 1);
+}
+
+/* Subdivision resolution per given polygon's ptex faces. */
+BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution)
+{
+ return (poly->totloop == 4) ? (resolution)
+ : ((resolution >> 1) + 1);
+}
+
+/* =============================================================================
+ * Context which is passed to all threaded tasks.
+ */
+
+typedef struct SubdivForeachTaskContext {
+ const Mesh *coarse_mesh;
+ const SubdivToMeshSettings *settings;
+ /* Callbacks. */
+ const SubdivForeachContext *foreach_context;
+ /* Counters of geometry in subdivided mesh, initialized as a part of
+ * offsets calculation.
+ */
+ int num_subdiv_vertices;
+ int num_subdiv_edges;
+ int num_subdiv_loops;
+ int num_subdiv_polygons;
+ /* Offsets of various geometry in the subdivision mesh arrays. */
+ int vertices_corner_offset;
+ int vertices_edge_offset;
+ int vertices_inner_offset;
+ int edge_boundary_offset;
+ int edge_inner_offset;
+ /* Indexed by coarse polygon index, indicates offset in subdivided mesh
+ * vertices, edges and polygons arrays, where first element of the poly
+ * begins.
+ */
+ int *subdiv_vertex_offset;
+ int *subdiv_edge_offset;
+ int *subdiv_polygon_offset;
+ /* Indexed by base face index, element indicates total number of ptex faces
+ * created for preceding base faces.
+ */
+ int *face_ptex_offset;
+ /* Bitmap indicating whether vertex was used already or not.
+ * - During patch evaluation indicates whether coarse vertex was already
+ * evaluated and its position on limit is already known.
+ */
+ BLI_bitmap *coarse_vertices_used_map;
+ /* Bitmap indicating whether edge was used already or not. This includes:
+ * - During context initialization it indicates whether subdivided vertices
+ * for corresponding edge were already calculated or not.
+ * - During patch evaluation it indicates whether vertices along this edge
+ * were already evaluated.
+ */
+ BLI_bitmap *coarse_edges_used_map;
+} SubdivForeachTaskContext;
+
+/* NOTE: Expects edge map to be zeroed. */
+static void subdiv_foreach_ctx_count(SubdivForeachTaskContext *ctx)
+{
+ /* Reset counters. */
+ ctx->num_subdiv_vertices = 0;
+ ctx->num_subdiv_edges = 0;
+ ctx->num_subdiv_loops = 0;
+ ctx->num_subdiv_polygons = 0;
+ /* Static geometry counters. */
+ const int resolution = ctx->settings->resolution;
+ const int no_quad_patch_resolution = ((resolution >> 1) + 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_inner_vertices_per_quad = (resolution - 2) * (resolution - 2);
+ const int num_inner_vertices_per_noquad_patch =
+ (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 2);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ ctx->num_subdiv_vertices = coarse_mesh->totvert;
+ ctx->num_subdiv_edges =
+ coarse_mesh->totedge * (num_subdiv_vertices_per_coarse_edge + 1);
+ /* Calculate extra vertices and edges createdd by non-loose geometry. */
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner];
+ const bool is_edge_used =
+ BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, loop->e);
+ /* Edges which aren't counted yet. */
+ if (!is_edge_used) {
+ BLI_BITMAP_ENABLE(ctx->coarse_edges_used_map, loop->e);
+ ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge;
+ }
+ }
+ /* Inner vertices of polygon. */
+ if (num_ptex_faces_per_poly == 1) {
+ ctx->num_subdiv_vertices += num_inner_vertices_per_quad;
+ ctx->num_subdiv_edges +=
+ num_edges_per_ptex_face_get(resolution - 2) +
+ 4 * num_subdiv_vertices_per_coarse_edge;
+ ctx->num_subdiv_polygons += num_polys_per_ptex_get(resolution);
+ }
+ else {
+ ctx->num_subdiv_vertices +=
+ 1 +
+ num_ptex_faces_per_poly * (no_quad_patch_resolution - 2) +
+ num_ptex_faces_per_poly * num_inner_vertices_per_noquad_patch;
+ ctx->num_subdiv_edges +=
+ num_ptex_faces_per_poly *
+ (num_inner_edges_per_ptex_face_get(
+ no_quad_patch_resolution - 1) +
+ (no_quad_patch_resolution - 2) +
+ num_subdiv_vertices_per_coarse_edge);
+ if (no_quad_patch_resolution >= 3) {
+ ctx->num_subdiv_edges += coarse_poly->totloop;
+ }
+ ctx->num_subdiv_polygons +=
+ num_ptex_faces_per_poly *
+ num_polys_per_ptex_get(no_quad_patch_resolution);
+ }
+ }
+ /* Calculate extra vertices createdd by loose edges. */
+ for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
+ if (!BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, edge_index)) {
+ ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge;
+ }
+ }
+ ctx->num_subdiv_loops = ctx->num_subdiv_polygons * 4;
+}
+
+static void subdiv_foreach_ctx_init_offsets(SubdivForeachTaskContext *ctx)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int resolution = ctx->settings->resolution;
+ const int resolution_2 = resolution - 2;
+ const int resolution_2_squared = resolution_2 * resolution_2;
+ const int no_quad_patch_resolution = ((resolution >> 1) + 1);
+ const int num_irregular_vertices_per_patch =
+ (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ /* Constant offsets in arrays. */
+ ctx->vertices_corner_offset = 0;
+ ctx->vertices_edge_offset = coarse_mesh->totvert;
+ ctx->vertices_inner_offset =
+ ctx->vertices_edge_offset +
+ coarse_mesh->totedge * num_subdiv_vertices_per_coarse_edge;
+ ctx->edge_boundary_offset = 0;
+ ctx->edge_inner_offset =
+ ctx->edge_boundary_offset +
+ coarse_mesh->totedge * num_subdiv_edges_per_coarse_edge;
+ /* "Indexed" offsets. */
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ int vertex_offset = 0;
+ int edge_offset = 0;
+ int polygon_offset = 0;
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ ctx->subdiv_vertex_offset[poly_index] = vertex_offset;
+ ctx->subdiv_edge_offset[poly_index] = edge_offset;
+ ctx->subdiv_polygon_offset[poly_index] = polygon_offset;
+ if (num_ptex_faces_per_poly == 1) {
+ vertex_offset += resolution_2_squared;
+ edge_offset += num_edges_per_ptex_face_get(resolution - 2) +
+ 4 * num_subdiv_vertices_per_coarse_edge;
+ polygon_offset += num_polys_per_ptex_get(resolution);
+ }
+ else {
+ vertex_offset +=
+ 1 +
+ num_ptex_faces_per_poly * num_irregular_vertices_per_patch;
+ edge_offset +=
+ num_ptex_faces_per_poly *
+ (num_inner_edges_per_ptex_face_get(
+ no_quad_patch_resolution - 1) +
+ (no_quad_patch_resolution - 2) +
+ num_subdiv_vertices_per_coarse_edge);
+ if (no_quad_patch_resolution >= 3) {
+ edge_offset += coarse_poly->totloop;
+ }
+ polygon_offset +=
+ num_ptex_faces_per_poly *
+ num_polys_per_ptex_get(no_quad_patch_resolution);
+ }
+ }
+}
+
+static void subdiv_foreach_ctx_init(Subdiv *subdiv,
+ SubdivForeachTaskContext *ctx)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ /* Allocate maps and offsets. */
+ ctx->coarse_vertices_used_map =
+ BLI_BITMAP_NEW(coarse_mesh->totvert, "vertices used map");
+ ctx->coarse_edges_used_map =
+ BLI_BITMAP_NEW(coarse_mesh->totedge, "edges used map");
+ ctx->subdiv_vertex_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_vertex_offset),
+ "vertex_offset");
+ ctx->subdiv_edge_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_edge_offset),
+ "subdiv_edge_offset");
+ ctx->subdiv_polygon_offset = MEM_malloc_arrayN(
+ coarse_mesh->totpoly,
+ sizeof(*ctx->subdiv_polygon_offset),
+ "subdiv_edge_offset");
+ /* Initialize all offsets. */
+ subdiv_foreach_ctx_init_offsets(ctx);
+ /* Calculate number of geometry in the result subdivision mesh. */
+ subdiv_foreach_ctx_count(ctx);
+ /* Re-set maps which were used at this step. */
+ BLI_BITMAP_SET_ALL(ctx->coarse_edges_used_map, false, coarse_mesh->totedge);
+ ctx->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+}
+
+static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
+{
+ MEM_freeN(ctx->coarse_vertices_used_map);
+ MEM_freeN(ctx->coarse_edges_used_map);
+ MEM_freeN(ctx->subdiv_vertex_offset);
+ MEM_freeN(ctx->subdiv_edge_offset);
+ MEM_freeN(ctx->subdiv_polygon_offset);
+}
+
+/* =============================================================================
+ * Vertex traversal process.
+ */
+
+/* Traversal of corner vertices. They are coming from coarse vertices. */
+
+static void subdiv_foreach_corner_vertices_regular_do(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromCornerCb vertex_corner,
+ bool check_usage)
+{
+ const float weights[4][2] = {{0.0f, 0.0f},
+ {1.0f, 0.0f},
+ {1.0f, 1.0f},
+ {0.0f, 1.0f}};
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map,
+ coarse_loop->v))
+ {
+ continue;
+ }
+ const int coarse_vertex_index = coarse_loop->v;
+ const int subdiv_vertex_index =
+ ctx->vertices_corner_offset + coarse_vertex_index;
+ const float u = weights[corner][0];
+ const float v = weights[corner][1];
+ vertex_corner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, v,
+ coarse_vertex_index,
+ coarse_poly_index,
+ 0,
+ subdiv_vertex_index);
+ }
+}
+
+static void subdiv_foreach_corner_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_corner_vertices_regular_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true);
+}
+
+static void subdiv_foreach_corner_vertices_special_do(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromCornerCb vertex_corner,
+ bool check_usage)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map,
+ coarse_loop->v))
+ {
+ continue;
+ }
+ const int coarse_vertex_index = coarse_loop->v;
+ const int subdiv_vertex_index =
+ ctx->vertices_corner_offset + coarse_vertex_index;
+ vertex_corner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ 0.0f, 0.0f,
+ coarse_vertex_index,
+ coarse_poly_index,
+ corner,
+ subdiv_vertex_index);
+ }
+}
+
+static void subdiv_foreach_corner_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_corner_vertices_special_do(
+ ctx, tls, coarse_poly, ctx->foreach_context->vertex_corner, true);
+}
+
+static void subdiv_foreach_corner_vertices(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_corner_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_corner_vertices_special(ctx, tls, coarse_poly);
+ }
+}
+
+static void subdiv_foreach_every_corner_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_corner_vertices_regular_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_every_corner,
+ false);
+}
+
+static void subdiv_foreach_every_corner_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_corner_vertices_special_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_every_corner,
+ false);
+}
+
+static void subdiv_foreach_every_corner_vertices(SubdivForeachTaskContext *ctx)
+{
+ if (ctx->foreach_context->vertex_every_corner == NULL) {
+ return;
+ }
+ const SubdivForeachContext *foreach_context = ctx->foreach_context;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ void *tls = NULL;
+ if (foreach_context->user_data_tls_size != 0) {
+ tls = MEM_mallocN(foreach_context->user_data_tls_size, "tls");
+ memcpy(tls,
+ foreach_context->user_data_tls,
+ foreach_context->user_data_tls_size);
+ }
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_every_corner_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_every_corner_vertices_special(ctx, tls, coarse_poly);
+ }
+ }
+ if (tls != NULL) {
+ MEM_freeN(tls);
+ }
+}
+
+/* Traverse of edge vertices. They are coming from coarse edges. */
+
+static void subdiv_foreach_edge_vertices_regular_do(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromEdgeCb vertex_edge,
+ bool check_usage)
+{
+ const int resolution = ctx->settings->resolution;
+ const int resolution_1 = resolution - 1;
+ const float inv_resolution_1 = 1.0f / (float)resolution_1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[poly_index];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const int coarse_edge_index = coarse_loop->e;
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map,
+ coarse_edge_index))
+ {
+ continue;
+ }
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int subdiv_vertex_index =
+ ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
+ for (int vertex_index = 0;
+ vertex_index < num_subdiv_vertices_per_coarse_edge;
+ vertex_index++, subdiv_vertex_index++)
+ {
+ float fac = (vertex_index + 1) * inv_resolution_1;
+ if (flip) {
+ fac = 1.0f - fac;
+ }
+ if (corner >= 2) {
+ fac = 1.0f - fac;
+ }
+ float u, v;
+ if ((corner & 1) == 0) {
+ u = fac;
+ v = (corner == 2) ? 1.0f : 0.0f;
+ }
+ else {
+ u = (corner == 1) ? 1.0f : 0.0f;
+ v = fac;
+ }
+ vertex_edge(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, v,
+ coarse_edge_index,
+ coarse_poly_index,
+ 0,
+ subdiv_vertex_index);
+ }
+ }
+}
+
+static void subdiv_foreach_edge_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_edge_vertices_regular_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_edge,
+ true);
+}
+
+static void subdiv_foreach_edge_vertices_special_do(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly,
+ SubdivForeachVertexFromEdgeCb vertex_edge,
+ bool check_usage)
+{
+ const int resolution = ctx->settings->resolution;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_vertices_per_ptex_edge = ((resolution >> 1) + 1);
+ const float inv_ptex_resolution_1 =
+ 1.0f / (float)(num_vertices_per_ptex_edge - 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_start_index = ctx->face_ptex_offset[poly_index];
+ int ptex_face_index = ptex_face_start_index;
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const int coarse_edge_index = coarse_loop->e;
+ if (check_usage &&
+ BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map,
+ coarse_edge_index))
+ {
+ continue;
+ }
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int subdiv_vertex_index =
+ ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
+ int veretx_delta = 1;
+ if (flip) {
+ subdiv_vertex_index += num_subdiv_vertices_per_coarse_edge - 1;
+ veretx_delta = -1;
+ }
+ for (int vertex_index = 1;
+ vertex_index < num_vertices_per_ptex_edge;
+ vertex_index++, subdiv_vertex_index += veretx_delta)
+ {
+ const float u = vertex_index * inv_ptex_resolution_1;
+ vertex_edge(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, 0.0f,
+ coarse_edge_index,
+ coarse_poly_index,
+ corner,
+ subdiv_vertex_index);
+ }
+ const int next_ptex_face_index =
+ ptex_face_start_index + (corner + 1) % coarse_poly->totloop;
+ for (int vertex_index = 1;
+ vertex_index < num_vertices_per_ptex_edge - 1;
+ vertex_index++, subdiv_vertex_index += veretx_delta)
+ {
+ const float v = 1.0f - vertex_index * inv_ptex_resolution_1;
+ vertex_edge(
+ ctx->foreach_context,
+ tls,
+ next_ptex_face_index,
+ 0.0f, v,
+ coarse_edge_index,
+ coarse_poly_index,
+ corner,
+ subdiv_vertex_index);
+ }
+ }
+}
+
+static void subdiv_foreach_edge_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_edge_vertices_special_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_edge,
+ true);
+}
+
+static void subdiv_foreach_edge_vertices(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_edge_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_edge_vertices_special(ctx, tls, coarse_poly);
+ }
+}
+
+static void subdiv_foreach_every_edge_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_edge_vertices_regular_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_every_edge,
+ false);
+}
+
+static void subdiv_foreach_every_edge_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ subdiv_foreach_edge_vertices_special_do(
+ ctx, tls, coarse_poly,
+ ctx->foreach_context->vertex_every_edge,
+ false);
+}
+
+static void subdiv_foreach_every_edge_vertices(SubdivForeachTaskContext *ctx)
+{
+ if (ctx->foreach_context->vertex_every_edge == NULL) {
+ return;
+ }
+ const SubdivForeachContext *foreach_context = ctx->foreach_context;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ void *tls = NULL;
+ if (foreach_context->user_data_tls_size != 0) {
+ tls = MEM_mallocN(foreach_context->user_data_tls_size, "tls");
+ memcpy(tls,
+ foreach_context->user_data_tls,
+ foreach_context->user_data_tls_size);
+ }
+ for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) {
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_every_edge_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_every_edge_vertices_special(ctx, tls, coarse_poly);
+ }
+ }
+ if (tls != NULL) {
+ MEM_freeN(tls);
+ }
+}
+
+/* Traversal of inner vertices, they are coming from ptex patches. */
+
+static void subdiv_foreach_inner_vertices_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
+ const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
+ int subdiv_vertex_index =
+ ctx->vertices_inner_offset + start_vertex_index;
+ for (int y = 1; y < resolution - 1; y++) {
+ const float v = y * inv_resolution_1;
+ for (int x = 1; x < resolution - 1; x++, subdiv_vertex_index++) {
+ const float u = x * inv_resolution_1;
+ ctx->foreach_context->vertex_inner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, v,
+ coarse_poly_index, 0,
+ subdiv_vertex_index);
+ }
+ }
+}
+
+static void subdiv_foreach_inner_vertices_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
+ const int ptex_face_resolution = ptex_face_resolution_get(
+ coarse_poly, resolution);
+ const float inv_ptex_face_resolution_1 =
+ 1.0f / (float)(ptex_face_resolution - 1);
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const int coarse_poly_index = coarse_poly - coarse_mesh->mpoly;
+ int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int start_vertex_index = ctx->subdiv_vertex_offset[coarse_poly_index];
+ int subdiv_vertex_index = ctx->vertices_inner_offset + start_vertex_index;
+ ctx->foreach_context->vertex_inner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ 1.0f, 1.0f,
+ coarse_poly_index, 0,
+ subdiv_vertex_index);
+ subdiv_vertex_index++;
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, ptex_face_index++)
+ {
+ for (int y = 1; y < ptex_face_resolution - 1; y++) {
+ const float v = y * inv_ptex_face_resolution_1;
+ for (int x = 1;
+ x < ptex_face_resolution; x++,
+ subdiv_vertex_index++)
+ {
+ const float u = x * inv_ptex_face_resolution_1;
+ ctx->foreach_context->vertex_inner(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index,
+ u, v,
+ coarse_poly_index, corner,
+ subdiv_vertex_index);
+ }
+ }
+ }
+}
+
+static void subdiv_foreach_inner_vertices(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_inner_vertices_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_inner_vertices_special(ctx, tls, coarse_poly);
+ }
+}
+
+/* Traverse all vertices which are emitted from given coarse polygon. */
+static void subdiv_foreach_vertices(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const int poly_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (ctx->foreach_context->vertex_corner != NULL) {
+ subdiv_foreach_corner_vertices(ctx, tls, coarse_poly);
+ }
+ if (ctx->foreach_context->vertex_edge != NULL) {
+ subdiv_foreach_edge_vertices(ctx, tls, coarse_poly);
+ }
+ if (ctx->foreach_context->vertex_inner != NULL) {
+ subdiv_foreach_inner_vertices(ctx, tls, coarse_poly);
+ }
+}
+
+/* =============================================================================
+ * Edge traversal process.
+ */
+
+/* TODO(sergey): Coarse edge are always NONE, consider getting rid of it. */
+static int subdiv_foreach_edges_row(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const int coarse_edge_index,
+ const int start_subdiv_edge_index,
+ const int start_vertex_index,
+ const int num_edges_per_row)
+{
+ int subdiv_edge_index = start_subdiv_edge_index;
+ int vertex_index = start_vertex_index;
+ for (int edge_index = 0;
+ edge_index < num_edges_per_row - 1;
+ edge_index++, subdiv_edge_index++)
+ {
+ const int v1 = vertex_index;
+ const int v2 = vertex_index + 1;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ coarse_edge_index,
+ subdiv_edge_index,
+ v1, v2);
+ vertex_index += 1;
+ }
+ return subdiv_edge_index;
+}
+
+/* TODO(sergey): Coarse edges are always NONE, consider getting rid of them. */
+static int subdiv_foreach_edges_column(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const int coarse_start_edge_index,
+ const int coarse_end_edge_index,
+ const int start_subdiv_edge_index,
+ const int start_vertex_index,
+ const int num_edges_per_row)
+{
+ int subdiv_edge_index = start_subdiv_edge_index;
+ int vertex_index = start_vertex_index;
+ for (int edge_index = 0;
+ edge_index < num_edges_per_row;
+ edge_index++, subdiv_edge_index++)
+ {
+ int coarse_edge_index = ORIGINDEX_NONE;
+ if (edge_index == 0) {
+ coarse_edge_index = coarse_start_edge_index;
+ }
+ else if (edge_index == num_edges_per_row - 1) {
+ coarse_edge_index = coarse_end_edge_index;
+ }
+ const int v1 = vertex_index;
+ const int v2 = vertex_index + num_edges_per_row;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ coarse_edge_index,
+ subdiv_edge_index,
+ v1, v2);
+ vertex_index += 1;
+ }
+ return subdiv_edge_index;
+}
+
+/* Defines edges between inner vertices of patch, and also edges to the
+ * boundary.
+ */
+
+/* Consider a subdivision of base face at level 1:
+ *
+ * y
+ * ^
+ * | (6) ---- (7) ---- (8)
+ * | | | |
+ * | (3) ---- (4) ---- (5)
+ * | | | |
+ * | (0) ---- (1) ---- (2)
+ * o---------------------------> x
+ *
+ * This is illustrate which parts of geometry is created by code below.
+ */
+
+static void subdiv_foreach_edges_all_patches_regular(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
+ const int resolution = ctx->settings->resolution;
+ const int start_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ int subdiv_edge_index =
+ ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index];
+ /* Traverse bottom row of edges (0-1, 1-2). */
+ subdiv_edge_index = subdiv_foreach_edges_row(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_vertex_index,
+ resolution - 2);
+ /* Traverse remaining edges. */
+ for (int row = 0; row < resolution - 3; row++) {
+ const int start_row_vertex_index =
+ start_vertex_index + row * (resolution - 2);
+ /* Traverse vertical columns.
+ *
+ * At first iteration it will be edges (0-3. 1-4, 2-5), then it
+ * will be (3-6, 4-7, 5-8) and so on.
+ */
+ subdiv_edge_index = subdiv_foreach_edges_column(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index,
+ resolution - 2);
+ /* Create horizontal edge row.
+ *
+ * At first iteration it will be edges (3-4, 4-5), then it will be
+ * (6-7, 7-8) and so on.
+ */
+ subdiv_edge_index = subdiv_foreach_edges_row(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index + resolution - 2,
+ resolution - 2);
+ }
+ /* Connect inner part of patch to boundary. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index = start_vertex_index;
+ int side_stride = 0;
+ /* Calculate starting veretx of corresponding inner part of ptex. */
+ if (corner == 0) {
+ side_stride = 1;
+ }
+ else if (corner == 1) {
+ side_start_index += resolution - 3;
+ side_stride = resolution - 2;
+ }
+ else if (corner == 2) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ num_subdiv_vertices_per_coarse_edge - 1;
+ side_stride = -1;
+ }
+ else if (corner == 3) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ (num_subdiv_vertices_per_coarse_edge - 1);
+ side_stride = -(resolution - 2);
+ }
+ for (int i = 0; i < resolution - 2; i++, subdiv_edge_index++) {
+ const int v1 = (flip)
+ ? (start_edge_vertex + (resolution - i - 3))
+ : (start_edge_vertex + i);
+ const int v2 = side_start_index + side_stride * i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ }
+ }
+}
+
+static void subdiv_foreach_edges_all_patches_special(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int poly_index = coarse_poly - coarse_mpoly;
+ const int resolution = ctx->settings->resolution;
+ const int ptex_face_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_face_inner_resolution = ptex_face_resolution - 2;
+ const int num_inner_vertices_per_ptex =
+ (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int center_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[poly_index];
+ const int start_vertex_index = center_vertex_index + 1;
+ int subdiv_edge_index =
+ ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index];
+ /* Traverse inner ptex edges. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int start_ptex_face_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex;
+ /* Similar steps to regular patch case. */
+ subdiv_edge_index = subdiv_foreach_edges_row(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_ptex_face_vertex_index,
+ ptex_face_inner_resolution + 1);
+ for (int row = 0; row < ptex_face_inner_resolution - 1; row++) {
+ const int start_row_vertex_index =
+ start_ptex_face_vertex_index +
+ row * (ptex_face_inner_resolution + 1);
+ subdiv_edge_index = subdiv_foreach_edges_column(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index,
+ ptex_face_inner_resolution + 1);
+ subdiv_edge_index = subdiv_foreach_edges_row(
+ ctx,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ start_row_vertex_index + ptex_face_inner_resolution + 1,
+ ptex_face_inner_resolution + 1);
+ }
+ }
+ /* Create connections between ptex faces. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int next_corner = (corner + 1) % coarse_poly->totloop;
+ int current_patch_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ int next_path_vertex_index =
+ start_vertex_index + next_corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - ptex_face_resolution + 1;
+ for (int row = 0;
+ row < ptex_face_inner_resolution;
+ row++, subdiv_edge_index++)
+ {
+ const int v1 = current_patch_vertex_index;
+ const int v2 = next_path_vertex_index;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ }
+ }
+ /* Create edges from center. */
+ if (ptex_face_resolution >= 3) {
+ for (int corner = 0;
+ corner < coarse_poly->totloop;
+ corner++, subdiv_edge_index++)
+ {
+ const int current_patch_end_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int v1 = center_vertex_index;
+ const int v2 = current_patch_end_vertex_index;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ }
+ }
+ /* Connect inner path of patch to boundary. */
+ const MLoop *prev_coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ {
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index;
+ if (ptex_face_resolution >= 3) {
+ side_start_index =
+ start_vertex_index + num_inner_vertices_per_ptex * corner;
+ }
+ else {
+ side_start_index = center_vertex_index;
+ }
+ for (int i = 0; i < ptex_face_resolution - 1;
+ i++,
+ subdiv_edge_index++)
+ {
+ const int v1 = (flip)
+ ? (start_edge_vertex + (resolution - i - 3))
+ : (start_edge_vertex + i);
+ const int v2 = side_start_index + i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ }
+ }
+ if (ptex_face_resolution >= 3) {
+ const MEdge *coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index =
+ start_vertex_index + num_inner_vertices_per_ptex * corner;
+ for (int i = 0;
+ i < ptex_face_resolution - 2;
+ i++, subdiv_edge_index++)
+ {
+ const int v1 = (flip)
+ ? (start_edge_vertex + (resolution - i - 3))
+ : (start_edge_vertex + i);
+ const int v2 = side_start_index +
+ (ptex_face_inner_resolution + 1) * i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ ORIGINDEX_NONE,
+ subdiv_edge_index,
+ v1, v2);
+ }
+ }
+ prev_coarse_loop = coarse_loop;
+ }
+}
+
+static void subdiv_foreach_edges_all_patches(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_edges_all_patches_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_edges_all_patches_special(ctx, tls, coarse_poly);
+ }
+}
+
+static void subdiv_foreach_edges(SubdivForeachTaskContext *ctx,
+ void *tls,
+ int poly_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ subdiv_foreach_edges_all_patches(ctx, tls, coarse_poly);
+}
+
+static void subdiv_foreach_boundary_edges(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ int coarse_edge_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ const int resolution = ctx->settings->resolution;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ int subdiv_edge_index =
+ ctx->edge_boundary_offset +
+ coarse_edge_index * num_subdiv_edges_per_coarse_edge;
+ int last_vertex_index = ctx->vertices_corner_offset + coarse_edge->v1;
+ for (int i = 0;
+ i < num_subdiv_edges_per_coarse_edge - 1;
+ i++, subdiv_edge_index++)
+ {
+ const int v1 = last_vertex_index;
+ const int v2 =
+ ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge +
+ i;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ coarse_edge_index,
+ subdiv_edge_index,
+ v1, v2);
+ last_vertex_index = v2;
+ }
+ const int v1 = last_vertex_index;
+ const int v2 = ctx->vertices_corner_offset + coarse_edge->v2;
+ ctx->foreach_context->edge(
+ ctx->foreach_context,
+ tls,
+ coarse_edge_index,
+ subdiv_edge_index,
+ v1, v2);
+}
+
+/* =============================================================================
+ * Loops traversal.
+ */
+
+static void rotate_indices(const int rot, int *a, int *b, int *c, int *d)
+{
+ int values[4] = {*a, *b, *c, *d};
+ *a = values[(0 - rot + 4) % 4];
+ *b = values[(1 - rot + 4) % 4];
+ *c = values[(2 - rot + 4) % 4];
+ *d = values[(3 - rot + 4) % 4];
+}
+
+static void subdiv_foreach_loops_of_poly(
+ SubdivForeachTaskContext *ctx,
+ void *tls,
+ int subdiv_loop_start_index,
+ const int ptex_face_index,
+ const int coarse_poly_index,
+ const int coarse_corner_index,
+ const int rotation,
+ /*const*/ int v0, /*const*/ int e0,
+ /*const*/ int v1, /*const*/ int e1,
+ /*const*/ int v2, /*const*/ int e2,
+ /*const*/ int v3, /*const*/ int e3,
+ const float u, const float v,
+ const float du, const float dv)
+{
+ rotate_indices(rotation, &v0, &v1, &v2, &v3);
+ rotate_indices(rotation, &e0, &e1, &e2, &e3);
+ ctx->foreach_context->loop(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index, u, v,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 0,
+ v0, e0);
+ ctx->foreach_context->loop(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index, u + du, v,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 1,
+ v1, e1);
+ ctx->foreach_context->loop(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index, u + du, v + dv,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 2,
+ v2, e2);
+ ctx->foreach_context->loop(
+ ctx->foreach_context,
+ tls,
+ ptex_face_index, u, v + dv,
+ ORIGINDEX_NONE,
+ coarse_poly_index,
+ coarse_corner_index,
+ subdiv_loop_start_index + 3,
+ v3, e3);
+}
+
+static void subdiv_foreach_loops_regular(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_inner_resolution = ptex_resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1);
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int start_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[coarse_poly_index];
+ const int start_edge_index =
+ ctx->edge_inner_offset +
+ ctx->subdiv_edge_offset[coarse_poly_index];
+ const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index];
+ const int start_loop_index = 4 * start_poly_index;
+ const float du = inv_ptex_resolution_1;
+ const float dv = inv_ptex_resolution_1;
+ /* Hi-poly subdivided mesh. */
+ int subdiv_loop_index = start_loop_index;
+ /* Loops for inner part of ptex. */
+ for (int y = 1; y < ptex_resolution - 2; y++) {
+ const float v = y * inv_ptex_resolution_1;
+ const int inner_y = y - 1;
+ for (int x = 1; x < ptex_resolution - 2; x++, subdiv_loop_index += 4) {
+ const int inner_x = x - 1;
+ const float u = x * inv_ptex_resolution_1;
+ /* Vertex indices ordered counter-clockwise. */
+ const int v0 = start_vertex_index +
+ (inner_y * ptex_inner_resolution + inner_x);
+ const int v1 = v0 + 1;
+ const int v2 = v0 + ptex_inner_resolution + 1;
+ const int v3 = v0 + ptex_inner_resolution;
+ /* Edge indices ordered counter-clockwise. */
+ const int e0 = start_edge_index +
+ (inner_y * (2 * ptex_inner_resolution - 1) + inner_x);
+ const int e1 = e0 + ptex_inner_resolution;
+ const int e2 = e0 + (2 * ptex_inner_resolution - 1);
+ const int e3 = e0 + ptex_inner_resolution - 1;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index,
+ coarse_poly_index, 0,
+ 0,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ }
+ }
+ /* Loops for faces connecting inner ptex part with boundary. */
+ const MLoop *prev_coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ int side_start_index = start_vertex_index;
+ int side_stride = 0;
+ int v0 = ctx->vertices_corner_offset + coarse_loop->v;
+ int v3, e3;
+ int e2_offset, e2_stride;
+ float u, v, delta_u, delta_v;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
+ }
+ /* Calculate starting veretx of corresponding inner part of ptex. */
+ if (corner == 0) {
+ side_stride = 1;
+ e2_offset = 0;
+ e2_stride = 1;
+ u = 0.0f;
+ v = 0.0f;
+ delta_u = du;
+ delta_v = 0.0f;
+ }
+ else if (corner == 1) {
+ side_start_index += resolution - 3;
+ side_stride = resolution - 2;
+ e2_offset = 2 * num_subdiv_edges_per_coarse_edge - 4;
+ e2_stride = 2 * num_subdiv_edges_per_coarse_edge - 3;
+ u = 1.0f - du;
+ v = 0;
+ delta_u = 0.0f;
+ delta_v = dv;
+ }
+ else if (corner == 2) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ num_subdiv_vertices_per_coarse_edge - 1;
+ side_stride = -1;
+ e2_offset = num_edges_per_ptex_face_get(resolution - 2) - 1;
+ e2_stride = -1;
+ u = 1.0f - du;
+ v = 1.0f - dv;
+ delta_u = -du;
+ delta_v = 0.0f;
+ }
+ else if (corner == 3) {
+ side_start_index += num_subdiv_vertices_per_coarse_edge *
+ (num_subdiv_vertices_per_coarse_edge - 1);
+ side_stride = -(resolution - 2);
+ e2_offset = num_edges_per_ptex_face_get(resolution - 2) -
+ (2 * num_subdiv_edges_per_coarse_edge - 3);
+ e2_stride = -(2 * num_subdiv_edges_per_coarse_edge - 3);
+ u = 0.0f;
+ v = 1.0f - dv;
+ delta_u = 0.0f;
+ delta_v = -dv;
+ }
+ for (int i = 0; i < resolution - 2; i++, subdiv_loop_index += 4) {
+ int v1;
+ if (flip) {
+ v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ v1 = start_edge_vertex + i;
+ }
+ const int v2 = side_start_index + side_stride * i;
+ int e0;
+ if (flip) {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - i - 1;
+ }
+ else {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ i;
+ }
+ int e1 = start_edge_index +
+ num_edges_per_ptex_face_get(resolution - 2) +
+ corner * num_subdiv_vertices_per_coarse_edge +
+ i;
+ int e2;
+ if (i == 0) {
+ e2 = start_edge_index +
+ num_edges_per_ptex_face_get(resolution - 2) +
+ ((corner - 1 + coarse_poly->totloop) %
+ coarse_poly->totloop) *
+ num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ }
+ else {
+ e2 = start_edge_index + e2_offset + e2_stride * (i - 1);
+ }
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index,
+ coarse_poly_index, corner,
+ corner,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u + delta_u * i, v + delta_v * i, du, dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ prev_coarse_loop = coarse_loop;
+ }
+}
+
+static void subdiv_foreach_loops_special(SubdivForeachTaskContext *ctx,
+ void *tls,
+ const MPoly *coarse_poly)
+{
+ const int resolution = ctx->settings->resolution;
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const int coarse_poly_index = coarse_poly - coarse_mpoly;
+ const int ptex_face_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int ptex_face_inner_resolution = ptex_face_resolution - 2;
+ const float inv_ptex_resolution_1 =
+ 1.0f / (float)(ptex_face_resolution - 1);
+ const int num_inner_vertices_per_ptex =
+ (ptex_face_resolution - 1) * (ptex_face_resolution - 2);
+ const int num_inner_edges_per_ptex_face =
+ num_inner_edges_per_ptex_face_get(
+ ptex_face_inner_resolution + 1);
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const int num_subdiv_edges_per_coarse_edge = resolution - 1;
+ const int ptex_face_index = ctx->face_ptex_offset[coarse_poly_index];
+ const int center_vertex_index =
+ ctx->vertices_inner_offset +
+ ctx->subdiv_vertex_offset[coarse_poly_index];
+ const int start_vertex_index = center_vertex_index + 1;
+ const int start_inner_vertex_index = center_vertex_index + 1;
+ const int start_edge_index = ctx->edge_inner_offset +
+ ctx->subdiv_edge_offset[coarse_poly_index];
+ const int start_poly_index = ctx->subdiv_polygon_offset[coarse_poly_index];
+ const int start_loop_index = 4 * start_poly_index;
+ const float du = inv_ptex_resolution_1;
+ const float dv = inv_ptex_resolution_1;
+ /* Hi-poly subdivided mesh. */
+ int subdiv_loop_index = start_loop_index;
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int corner_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex;
+ const int corner_edge_index =
+ start_edge_index + corner * num_inner_edges_per_ptex_face;
+ for (int y = 1; y < ptex_face_inner_resolution; y++) {
+ const float v = y * inv_ptex_resolution_1;
+ const int inner_y = y - 1;
+ for (int x = 1;
+ x < ptex_face_inner_resolution + 1;
+ x++, subdiv_loop_index += 4)
+ {
+ const int inner_x = x - 1;
+ const float u = x * inv_ptex_resolution_1;
+ /* Vertex indices ordered counter-clockwise. */
+ const int v0 =
+ corner_vertex_index +
+ (inner_y * (ptex_face_inner_resolution + 1) + inner_x);
+ const int v1 = v0 + 1;
+ const int v2 = v0 + ptex_face_inner_resolution + 2;
+ const int v3 = v0 + ptex_face_inner_resolution + 1;
+ /* Edge indices ordered counter-clockwise. */
+ const int e0 = corner_edge_index +
+ (inner_y * (2 * ptex_face_inner_resolution + 1) + inner_x);
+ const int e1 = e0 + ptex_face_inner_resolution + 1;
+ const int e2 = e0 + (2 * ptex_face_inner_resolution + 1);
+ const int e3 = e0 + ptex_face_inner_resolution;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index + corner,
+ coarse_poly_index, corner,
+ 0,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ }
+ }
+ }
+ /* Create connections between ptex faces. */
+ for (int corner = 0; corner < coarse_poly->totloop; corner++) {
+ const int next_corner = (corner + 1) % coarse_poly->totloop;
+ const int corner_edge_index =
+ start_edge_index + corner * num_inner_edges_per_ptex_face;
+ const int next_corner_edge_index =
+ start_edge_index + next_corner * num_inner_edges_per_ptex_face;
+ int current_patch_vertex_index =
+ start_inner_vertex_index +
+ corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ int next_path_vertex_index =
+ start_inner_vertex_index +
+ next_corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - ptex_face_resolution + 1;
+ int v0 = current_patch_vertex_index;
+ int v1 = next_path_vertex_index;
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ int e0 = start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ corner * (ptex_face_resolution - 2);
+ int e1 = next_corner_edge_index + num_inner_edges_per_ptex_face -
+ ptex_face_resolution + 2;
+ int e3 = corner_edge_index + 2 * ptex_face_resolution - 4;
+ for (int row = 1;
+ row < ptex_face_inner_resolution;
+ row++, subdiv_loop_index += 4)
+ {
+ const int v2 = next_path_vertex_index;
+ const int v3 = current_patch_vertex_index;
+ const int e2 = e0 + 1;
+ const float u = row * du;
+ const float v = 1.0f - dv;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index + next_corner,
+ coarse_poly_index, next_corner,
+ 3,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ current_patch_vertex_index += ptex_face_inner_resolution + 1;
+ next_path_vertex_index += 1;
+ v0 = v3;
+ v1 = v2;
+ e0 = e2;
+ e1 += 1;
+ e3 += 2 * ptex_face_resolution - 3;
+ }
+ }
+ /* Create loops from center. */
+ if (ptex_face_resolution >= 3) {
+ const int start_center_edge_index =
+ start_edge_index +
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution) * coarse_poly->totloop;
+ const int start_boundary_edge =
+ start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution - 1;
+ for (int corner = 0, prev_corner = coarse_poly->totloop - 1;
+ corner < coarse_poly->totloop;
+ prev_corner = corner, corner++, subdiv_loop_index += 4)
+ {
+ const int corner_edge_index =
+ start_edge_index +
+ corner * num_inner_edges_per_ptex_face;
+ const int current_patch_end_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int prev_current_patch_end_vertex_index =
+ start_vertex_index + prev_corner *
+ num_inner_vertices_per_ptex +
+ num_inner_vertices_per_ptex - 1;
+ const int v0 = center_vertex_index;
+ const int v1 = prev_current_patch_end_vertex_index;
+ const int v2 = current_patch_end_vertex_index - 1;
+ const int v3 = current_patch_end_vertex_index;
+ const int e0 = start_center_edge_index + prev_corner;
+ const int e1 = start_boundary_edge +
+ prev_corner * (ptex_face_inner_resolution);
+ const int e2 = corner_edge_index +
+ num_inner_edges_per_ptex_face - 1;
+ const int e3 = start_center_edge_index + corner;
+ const float u = 1.0f - du;
+ const float v = 1.0f - dv;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index,
+ ptex_face_index + corner,
+ coarse_poly_index, corner,
+ 2,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ }
+ }
+ /* Loops for faces connecting inner ptex part with boundary. */
+ const MLoop *prev_coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1];
+ for (int prev_corner = coarse_poly->totloop - 1, corner = 0;
+ corner < coarse_poly->totloop;
+ prev_corner = corner, corner++)
+ {
+ const MLoop *coarse_loop =
+ &coarse_mloop[coarse_poly->loopstart + corner];
+ const MEdge *coarse_edge = &coarse_medge[coarse_loop->e];
+ const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e];
+ const bool flip = (coarse_edge->v2 == coarse_loop->v);
+ const int start_edge_vertex = ctx->vertices_edge_offset +
+ coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ const int corner_vertex_index =
+ start_vertex_index + corner * num_inner_vertices_per_ptex;
+ const int corner_edge_index =
+ start_edge_index + corner * num_inner_edges_per_ptex_face;
+ /* Create loops for polygons along U axis. */
+ int v0 = ctx->vertices_corner_offset + coarse_loop->v;
+ int v3, e3;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ e3 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge;
+ }
+ for (int i = 0;
+ i <= ptex_face_inner_resolution;
+ i++, subdiv_loop_index += 4)
+ {
+ int v1;
+ if (flip) {
+ v1 = start_edge_vertex + (resolution - i - 3);
+ }
+ else {
+ v1 = start_edge_vertex + i;
+ }
+ int v2;
+ if (ptex_face_inner_resolution >= 1) {
+ v2 = corner_vertex_index + i;
+ }
+ else {
+ v2 = center_vertex_index;
+ }
+ int e0;
+ if (flip) {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - i - 1;
+ }
+ else {
+ e0 = ctx->edge_boundary_offset +
+ coarse_loop->e * num_subdiv_edges_per_coarse_edge +
+ i;
+ }
+ int e1 = start_edge_index +
+ corner * (2 * ptex_face_inner_resolution + 1);
+ if (ptex_face_resolution >= 3) {
+ e1 += coarse_poly->totloop * (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ i;
+ }
+ int e2 = 0;
+ if (i == 0 && ptex_face_resolution >= 3) {
+ e2 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ corner * (2 * ptex_face_inner_resolution + 1) +
+ ptex_face_inner_resolution + 1;
+ }
+ else if (i == 0 && ptex_face_resolution < 3) {
+ e2 = start_edge_index +
+ prev_corner * (2 * ptex_face_inner_resolution + 1);
+ }
+ else {
+ e2 = corner_edge_index + i - 1;
+ }
+ const float u = du * i;
+ const float v = 0.0f;
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index + corner,
+ coarse_poly_index, corner,
+ 0,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ /* Create loops for polygons along V axis. */
+ const bool flip_prev = (prev_coarse_edge->v2 == coarse_loop->v);
+ v0 = corner_vertex_index;
+ if (prev_coarse_loop->v == prev_coarse_edge->v1) {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge +
+ num_subdiv_vertices_per_coarse_edge - 1;
+ }
+ else {
+ v3 = ctx->vertices_edge_offset +
+ prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge;
+ }
+ e3 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ corner * (2 * ptex_face_inner_resolution + 1) +
+ ptex_face_inner_resolution + 1;
+ for (int i = 0;
+ i <= ptex_face_inner_resolution - 1;
+ i++, subdiv_loop_index += 4)
+ {
+ int v1;
+ int e0, e1;
+ if (i == ptex_face_inner_resolution - 1) {
+ v1 = start_vertex_index +
+ prev_corner * num_inner_vertices_per_ptex +
+ ptex_face_inner_resolution;
+ e1 = start_edge_index +
+ coarse_poly->totloop *
+ (num_inner_edges_per_ptex_face +
+ ptex_face_inner_resolution + 1) +
+ prev_corner * (2 * ptex_face_inner_resolution + 1) +
+ ptex_face_inner_resolution;
+ e0 = start_edge_index +
+ coarse_poly->totloop * num_inner_edges_per_ptex_face +
+ prev_corner * ptex_face_inner_resolution;
+ }
+ else {
+ v1 = v0 + ptex_face_inner_resolution + 1;
+ e0 = corner_edge_index + ptex_face_inner_resolution +
+ i * (2 * ptex_face_inner_resolution + 1);
+ e1 = e3 + 1;
+ }
+ int v2 = flip_prev ? v3 - 1 : v3 + 1;
+ int e2;
+ if (flip_prev) {
+ e2 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e *
+ num_subdiv_edges_per_coarse_edge +
+ num_subdiv_edges_per_coarse_edge - 2 - i;
+ }
+ else {
+ e2 = ctx->edge_boundary_offset +
+ prev_coarse_loop->e *
+ num_subdiv_edges_per_coarse_edge + 1 + i;
+ }
+ const float u = 0.0f;
+ const float v = du * (i + 1);
+ subdiv_foreach_loops_of_poly(
+ ctx, tls, subdiv_loop_index, ptex_face_index + corner,
+ coarse_poly_index, corner,
+ 1,
+ v0, e0, v1, e1, v2, e2, v3, e3,
+ u, v, du, dv);
+ v0 = v1;
+ v3 = v2;
+ e3 = e1;
+ }
+ prev_coarse_loop = coarse_loop;
+ }
+}
+
+static void subdiv_foreach_loops(SubdivForeachTaskContext *ctx,
+ void *tls,
+ int poly_index)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ if (coarse_poly->totloop == 4) {
+ subdiv_foreach_loops_regular(ctx, tls, coarse_poly);
+ }
+ else {
+ subdiv_foreach_loops_special(ctx, tls, coarse_poly);
+ }
+}
+
+/* =============================================================================
+ * Polygons traverse process.
+ */
+
+static void subdiv_foreach_polys(SubdivForeachTaskContext *ctx,
+ void *tls,
+ int poly_index)
+{
+ const int resolution = ctx->settings->resolution;
+ const int start_poly_index = ctx->subdiv_polygon_offset[poly_index];
+ /* Base/coarse mesh information. */
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[poly_index];
+ const int num_ptex_faces_per_poly =
+ num_ptex_faces_per_poly_get(coarse_poly);
+ const int ptex_resolution =
+ ptex_face_resolution_get(coarse_poly, resolution);
+ const int num_polys_per_ptex = num_polys_per_ptex_get(ptex_resolution);
+ const int num_loops_per_ptex = 4 * num_polys_per_ptex;
+ const int start_loop_index = 4 * start_poly_index;
+ /* Hi-poly subdivided mesh. */
+ int subdiv_polyon_index = start_poly_index;
+ for (int ptex_of_poly_index = 0;
+ ptex_of_poly_index < num_ptex_faces_per_poly;
+ ptex_of_poly_index++)
+ {
+ for (int subdiv_poly_index = 0;
+ subdiv_poly_index < num_polys_per_ptex;
+ subdiv_poly_index++, subdiv_polyon_index++)
+ {
+ const int loopstart = start_loop_index +
+ (ptex_of_poly_index * num_loops_per_ptex) +
+ (subdiv_poly_index * 4);
+ ctx->foreach_context->poly(
+ ctx->foreach_context,
+ tls,
+ poly_index,
+ subdiv_polyon_index,
+ loopstart, 4);
+ }
+ }
+}
+
+/* =============================================================================
+ * Loose elements traverse process.
+ */
+
+static void subdiv_foreach_loose_vertices_task(
+ void *__restrict userdata,
+ const int coarse_vertex_index,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ if (BLI_BITMAP_TEST_BOOL(ctx->coarse_vertices_used_map,
+ coarse_vertex_index))
+ {
+ /* Vertex is not loose, was handled when handling polygons. */
+ return;
+ }
+ const int subdiv_vertex_index =
+ ctx->vertices_corner_offset + coarse_vertex_index;
+ ctx->foreach_context->vertex_loose(
+ ctx->foreach_context,
+ tls->userdata_chunk,
+ coarse_vertex_index,
+ subdiv_vertex_index);
+}
+
+static void subdiv_foreach_vertices_of_loose_edges_task(
+ void *__restrict userdata,
+ const int coarse_edge_index,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ if (BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, coarse_edge_index)) {
+ /* Vertex is not loose, was handled when handling polygons. */
+ return;
+ }
+ const int resolution = ctx->settings->resolution;
+ const int resolution_1 = resolution - 1;
+ const float inv_resolution_1 = 1.0f / (float)resolution_1;
+ const int num_subdiv_vertices_per_coarse_edge = resolution - 2;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index];
+ /* Subdivion vertices which corresponds to edge's v1 and v2. */
+ const int subdiv_v1_index =
+ ctx->vertices_corner_offset + coarse_edge->v1;
+ const int subdiv_v2_index =
+ ctx->vertices_corner_offset + coarse_edge->v2;
+ /* First subdivided inner vertex of the edge. */
+ const int subdiv_start_vertex =
+ ctx->vertices_edge_offset +
+ coarse_edge_index * num_subdiv_vertices_per_coarse_edge;
+ /* Perform interpolation. */
+ for (int i = 0; i < resolution; i++) {
+ const float u = i * inv_resolution_1;
+ int subdiv_vertex_index;
+ if (i == 0) {
+ subdiv_vertex_index = subdiv_v1_index;
+ }
+ else if (i == resolution - 1) {
+ subdiv_vertex_index = subdiv_v2_index;
+ }
+ else {
+ subdiv_vertex_index = subdiv_start_vertex + (i - 1);
+ }
+ ctx->foreach_context->vertex_of_loose_edge(
+ ctx->foreach_context,
+ tls->userdata_chunk,
+ coarse_edge_index,
+ u,
+ subdiv_vertex_index);
+ }
+}
+
+/* =============================================================================
+ * Subdivision process entry points.
+ */
+
+static void subdiv_foreach_task(
+ void *__restrict userdata,
+ const int poly_index,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ /* Traverse hi-poly vertex coordinates and normals. */
+ subdiv_foreach_vertices(ctx, tls->userdata_chunk, poly_index);
+ /* Traverse mesh geometry for the given base poly index. */
+ if (ctx->foreach_context->edge != NULL) {
+ subdiv_foreach_edges(ctx, tls->userdata_chunk, poly_index);
+ }
+ if (ctx->foreach_context->loop != NULL) {
+ subdiv_foreach_loops(ctx, tls->userdata_chunk, poly_index);
+ }
+ if (ctx->foreach_context->poly != NULL) {
+ subdiv_foreach_polys(ctx, tls->userdata_chunk, poly_index);
+ }
+}
+
+static void subdiv_foreach_boundary_edges_task(
+ void *__restrict userdata,
+ const int edge_index,
+ const ParallelRangeTLS *__restrict tls)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ subdiv_foreach_boundary_edges(ctx, tls->userdata_chunk, edge_index);
+}
+
+static void subdiv_foreach_finalize(void *__restrict userdata,
+ void *__restrict userdata_chunk)
+{
+ SubdivForeachTaskContext *ctx = userdata;
+ ctx->foreach_context->user_data_tls_free(userdata_chunk);
+}
+
+bool BKE_subdiv_foreach_subdiv_geometry(
+ Subdiv *subdiv,
+ const SubdivForeachContext *context,
+ const SubdivToMeshSettings *mesh_settings,
+ const Mesh *coarse_mesh)
+{
+ SubdivForeachTaskContext ctx = {0};
+ ctx.coarse_mesh = coarse_mesh;
+ ctx.settings = mesh_settings;
+ ctx.foreach_context = context;
+ subdiv_foreach_ctx_init(subdiv, &ctx);
+ if (context->topology_info != NULL) {
+ if (!context->topology_info(context,
+ ctx.num_subdiv_vertices,
+ ctx.num_subdiv_edges,
+ ctx.num_subdiv_loops,
+ ctx.num_subdiv_polygons))
+ {
+ subdiv_foreach_ctx_free(&ctx);
+ return false;
+ }
+ }
+ /* Single threaded passes to average displacement on the corner vertices
+ * and boundary edges.
+ */
+ subdiv_foreach_every_corner_vertices(&ctx);
+ subdiv_foreach_every_edge_vertices(&ctx);
+ /* Threaded traversal of the rest of topology. */
+ ParallelRangeSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.userdata_chunk = context->user_data_tls;
+ parallel_range_settings.userdata_chunk_size = context->user_data_tls_size;
+ if (context->user_data_tls_free != NULL) {
+ parallel_range_settings.func_finalize = subdiv_foreach_finalize;
+ }
+ BLI_task_parallel_range(0, coarse_mesh->totpoly,
+ &ctx,
+ subdiv_foreach_task,
+ &parallel_range_settings);
+ if (context->vertex_loose != NULL) {
+ BLI_task_parallel_range(0, coarse_mesh->totvert,
+ &ctx,
+ subdiv_foreach_loose_vertices_task,
+ &parallel_range_settings);
+ }
+ if (context->vertex_of_loose_edge != NULL) {
+ BLI_task_parallel_range(0, coarse_mesh->totedge,
+ &ctx,
+ subdiv_foreach_vertices_of_loose_edges_task,
+ &parallel_range_settings);
+ }
+ if (context->edge != NULL) {
+ BLI_task_parallel_range(0, coarse_mesh->totedge,
+ &ctx,
+ subdiv_foreach_boundary_edges_task,
+ &parallel_range_settings);
+ }
+ subdiv_foreach_ctx_free(&ctx);
+ return true;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_inline.h b/source/blender/blenkernel/intern/subdiv_inline.h
new file mode 100644
index 00000000000..7eebde48bdc
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_inline.h
@@ -0,0 +1,80 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_inline.h
+ * \ingroup bke
+ */
+
+#ifndef __SUBDIV_INLINE_H__
+#define __SUBDIV_INLINE_H__
+
+#include "BLI_assert.h"
+#include "BLI_compiler_compat.h"
+
+#include "BKE_subdiv.h"
+
+BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(
+ const float ptex_u, const float ptex_v,
+ float *r_grid_u, float *r_grid_v)
+{
+ *r_grid_u = 1.0f - ptex_v;
+ *r_grid_v = 1.0f - ptex_u;
+}
+
+BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level)
+{
+ return (1 << (level - 1)) + 1;
+}
+
+BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(
+ const float u, const float v,
+ float *r_u, float *r_v)
+{
+ int corner;
+ if (u <= 0.5f && v <= 0.5f) {
+ corner = 0;
+ *r_u = 2.0f * u;
+ *r_v = 2.0f * v;
+ }
+ else if (u > 0.5f && v <= 0.5f) {
+ corner = 1;
+ *r_u = 2.0f * v;
+ *r_v = 2.0f * (1.0f - u);
+ }
+ else if (u > 0.5f && v > 0.5f) {
+ corner = 2;
+ *r_u = 2.0f * (1.0f - u);
+ *r_v = 2.0f * (1.0f - v);
+ }
+ else {
+ BLI_assert(u <= 0.5f && v >= 0.5f);
+ corner = 3;
+ *r_u = 2.0f * (1.0f - v);
+ *r_v = 2.0f * u;
+ }
+ return corner;
+}
+
+#endif /* __SUBDIV_INLINE_H__ */
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
new file mode 100644
index 00000000000..d8d4014b3cd
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -0,0 +1,1148 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_mesh.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv_mesh.h"
+
+#include "atomic_ops.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_bitmap.h"
+#include "BLI_math_vector.h"
+#include "BLI_task.h"
+
+#include "BKE_mesh.h"
+#include "BKE_key.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+
+#include "MEM_guardedalloc.h"
+
+/* =============================================================================
+ * Subdivision context.
+ */
+
+typedef struct SubdivMeshContext {
+ const Mesh *coarse_mesh;
+ Subdiv *subdiv;
+ Mesh *subdiv_mesh;
+ /* Cached custom data arrays for fastter access. */
+ int *vert_origindex;
+ int *edge_origindex;
+ int *loop_origindex;
+ int *poly_origindex;
+ /* UV layers interpolation. */
+ int num_uv_layers;
+ MLoopUV *uv_layers[MAX_MTFACE];
+} SubdivMeshContext;
+
+static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
+{
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ ctx->num_uv_layers =
+ CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV);
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) {
+ ctx->uv_layers[layer_index] = CustomData_get_layer_n(
+ &subdiv_mesh->ldata, CD_MLOOPUV, layer_index);
+ }
+}
+
+static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
+{
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ /* Pointers to original indices layers. */
+ ctx->vert_origindex = CustomData_get_layer(
+ &subdiv_mesh->vdata, CD_ORIGINDEX);
+ ctx->edge_origindex = CustomData_get_layer(
+ &subdiv_mesh->edata, CD_ORIGINDEX);
+ ctx->loop_origindex = CustomData_get_layer(
+ &subdiv_mesh->ldata, CD_ORIGINDEX);
+ ctx->poly_origindex = CustomData_get_layer(
+ &subdiv_mesh->pdata, CD_ORIGINDEX);
+ /* UV layers interpolation. */
+ subdiv_mesh_ctx_cache_uv_layers(ctx);
+}
+
+/* =============================================================================
+ * Loop custom data copy helpers.
+ */
+
+typedef struct LoopsOfPtex {
+ /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */
+ const MLoop *first_loop;
+ /* Last loop of the ptex, starts at ptex (0, 0) and goes in v direction. */
+ const MLoop *last_loop;
+ /* For quad coarse faces only. */
+ const MLoop *second_loop;
+ const MLoop *third_loop;
+} LoopsOfPtex;
+
+static void loops_of_ptex_get(
+ const SubdivMeshContext *ctx,
+ LoopsOfPtex *loops_of_ptex,
+ const MPoly *coarse_poly,
+ const int ptex_of_poly_index)
+{
+ const MLoop *coarse_mloop = ctx->coarse_mesh->mloop;
+ const int first_ptex_loop_index =
+ coarse_poly->loopstart + ptex_of_poly_index;
+ /* Loop which look in the (opposite) V direction of the current
+ * ptex face.
+ *
+ * TODO(sergey): Get rid of using module on every iteration.
+ */
+ const int last_ptex_loop_index =
+ coarse_poly->loopstart +
+ (ptex_of_poly_index + coarse_poly->totloop - 1) %
+ coarse_poly->totloop;
+ loops_of_ptex->first_loop = &coarse_mloop[first_ptex_loop_index];
+ loops_of_ptex->last_loop = &coarse_mloop[last_ptex_loop_index];
+ if (coarse_poly->totloop == 4) {
+ loops_of_ptex->second_loop = loops_of_ptex->first_loop + 1;
+ loops_of_ptex->third_loop = loops_of_ptex->first_loop + 2;
+ }
+ else {
+ loops_of_ptex->second_loop = NULL;
+ loops_of_ptex->third_loop = NULL;
+ }
+}
+
+/* =============================================================================
+ * Vertex custom data interpolation helpers.
+ */
+
+/* TODO(sergey): Somehow de-duplicate with loops storage, without too much
+ * exception cases all over the code.
+ */
+
+typedef struct VerticesForInterpolation {
+ /* This field points to a vertex data which is to be used for interpolation.
+ * The idea is to avoid unnecessary allocations for regular faces, where
+ * we can simply
+ */
+ const CustomData *vertex_data;
+ /* Vertices data calculated for ptex corners. There are always 4 elements
+ * in this custom data, aligned the following way:
+ *
+ * index 0 -> uv (0, 0)
+ * index 1 -> uv (0, 1)
+ * index 2 -> uv (1, 1)
+ * index 3 -> uv (1, 0)
+ *
+ * Is allocated for non-regular faces (triangles and n-gons).
+ */
+ CustomData vertex_data_storage;
+ bool vertex_data_storage_allocated;
+ /* Infices within vertex_data to interpolate for. The indices are aligned
+ * with uv coordinates in a similar way as indices in loop_data_storage.
+ */
+ int vertex_indices[4];
+} VerticesForInterpolation;
+
+static void vertex_interpolation_init(
+ const SubdivMeshContext *ctx,
+ VerticesForInterpolation *vertex_interpolation,
+ const MPoly *coarse_poly)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ if (coarse_poly->totloop == 4) {
+ vertex_interpolation->vertex_data = &coarse_mesh->vdata;
+ vertex_interpolation->vertex_indices[0] =
+ coarse_mloop[coarse_poly->loopstart + 0].v;
+ vertex_interpolation->vertex_indices[1] =
+ coarse_mloop[coarse_poly->loopstart + 1].v;
+ vertex_interpolation->vertex_indices[2] =
+ coarse_mloop[coarse_poly->loopstart + 2].v;
+ vertex_interpolation->vertex_indices[3] =
+ coarse_mloop[coarse_poly->loopstart + 3].v;
+ vertex_interpolation->vertex_data_storage_allocated = false;
+ }
+ else {
+ vertex_interpolation->vertex_data =
+ &vertex_interpolation->vertex_data_storage;
+ /* Allocate storage for loops corresponding to ptex corners. */
+ CustomData_copy(&ctx->coarse_mesh->vdata,
+ &vertex_interpolation->vertex_data_storage,
+ CD_MASK_EVERYTHING,
+ CD_CALLOC,
+ 4);
+ /* Initialize indices. */
+ vertex_interpolation->vertex_indices[0] = 0;
+ vertex_interpolation->vertex_indices[1] = 1;
+ vertex_interpolation->vertex_indices[2] = 2;
+ vertex_interpolation->vertex_indices[3] = 3;
+ vertex_interpolation->vertex_data_storage_allocated = true;
+ /* Interpolate center of poly right away, it stays unchanged for all
+ * ptex faces.
+ */
+ const float weight = 1.0f / (float)coarse_poly->totloop;
+ float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
+ int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
+ for (int i = 0; i < coarse_poly->totloop; ++i) {
+ weights[i] = weight;
+ indices[i] = coarse_mloop[coarse_poly->loopstart + i].v;
+ }
+ CustomData_interp(&coarse_mesh->vdata,
+ &vertex_interpolation->vertex_data_storage,
+ indices,
+ weights, NULL,
+ coarse_poly->totloop,
+ 2);
+ }
+}
+
+static void vertex_interpolation_from_corner(
+ const SubdivMeshContext *ctx,
+ VerticesForInterpolation *vertex_interpolation,
+ const MPoly *coarse_poly,
+ const int corner)
+{
+ if (coarse_poly->totloop == 4) {
+ /* Nothing to do, all indices and data is already assigned. */
+ }
+ else {
+ const CustomData *vertex_data = &ctx->coarse_mesh->vdata;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ LoopsOfPtex loops_of_ptex;
+ loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner);
+ /* Ptex face corner corresponds to a poly loop with same index. */
+ CustomData_copy_data(
+ vertex_data,
+ &vertex_interpolation->vertex_data_storage,
+ coarse_mloop[coarse_poly->loopstart + corner].v,
+ 0,
+ 1);
+ /* Interpolate remaining ptex face corners, which hits loops
+ * middle points.
+ *
+ * TODO(sergey): Re-use one of interpolation results from previous
+ * iteration.
+ */
+ const float weights[2] = {0.5f, 0.5f};
+ const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop;
+ const int last_loop_index = loops_of_ptex.last_loop - coarse_mloop;
+ const int first_indices[2] = {
+ coarse_mloop[first_loop_index].v,
+ coarse_mloop[coarse_poly->loopstart +
+ (first_loop_index - coarse_poly->loopstart + 1) %
+ coarse_poly->totloop].v};
+ const int last_indices[2] = {coarse_mloop[first_loop_index].v,
+ coarse_mloop[last_loop_index].v};
+ CustomData_interp(vertex_data,
+ &vertex_interpolation->vertex_data_storage,
+ first_indices,
+ weights, NULL,
+ 2,
+ 1);
+ CustomData_interp(vertex_data,
+ &vertex_interpolation->vertex_data_storage,
+ last_indices,
+ weights, NULL,
+ 2,
+ 3);
+ }
+}
+
+static void vertex_interpolation_end(
+ VerticesForInterpolation *vertex_interpolation)
+{
+ if (vertex_interpolation->vertex_data_storage_allocated) {
+ CustomData_free(&vertex_interpolation->vertex_data_storage, 4);
+ }
+}
+
+/* =============================================================================
+ * Loop custom data interpolation helpers.
+ */
+
+typedef struct LoopsForInterpolation {
+ /* This field points to a loop data which is to be used for interpolation.
+ * The idea is to avoid unnecessary allocations for regular faces, where
+ * we can simply
+ */
+ const CustomData *loop_data;
+ /* Loops data calculated for ptex corners. There are always 4 elements
+ * in this custom data, aligned the following way:
+ *
+ * index 0 -> uv (0, 0)
+ * index 1 -> uv (0, 1)
+ * index 2 -> uv (1, 1)
+ * index 3 -> uv (1, 0)
+ *
+ * Is allocated for non-regular faces (triangles and n-gons).
+ */
+ CustomData loop_data_storage;
+ bool loop_data_storage_allocated;
+ /* Infices within loop_data to interpolate for. The indices are aligned with
+ * uv coordinates in a similar way as indices in loop_data_storage.
+ */
+ int loop_indices[4];
+} LoopsForInterpolation;
+
+static void loop_interpolation_init(
+ const SubdivMeshContext *ctx,
+ LoopsForInterpolation *loop_interpolation,
+ const MPoly *coarse_poly)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ if (coarse_poly->totloop == 4) {
+ loop_interpolation->loop_data = &coarse_mesh->ldata;
+ loop_interpolation->loop_indices[0] = coarse_poly->loopstart + 0;
+ loop_interpolation->loop_indices[1] = coarse_poly->loopstart + 1;
+ loop_interpolation->loop_indices[2] = coarse_poly->loopstart + 2;
+ loop_interpolation->loop_indices[3] = coarse_poly->loopstart + 3;
+ loop_interpolation->loop_data_storage_allocated = false;
+ }
+ else {
+ loop_interpolation->loop_data = &loop_interpolation->loop_data_storage;
+ /* Allocate storage for loops corresponding to ptex corners. */
+ CustomData_copy(&ctx->coarse_mesh->ldata,
+ &loop_interpolation->loop_data_storage,
+ CD_MASK_EVERYTHING,
+ CD_CALLOC,
+ 4);
+ /* Initialize indices. */
+ loop_interpolation->loop_indices[0] = 0;
+ loop_interpolation->loop_indices[1] = 1;
+ loop_interpolation->loop_indices[2] = 2;
+ loop_interpolation->loop_indices[3] = 3;
+ loop_interpolation->loop_data_storage_allocated = true;
+ /* Interpolate center of poly right away, it stays unchanged for all
+ * ptex faces.
+ */
+ const float weight = 1.0f / (float)coarse_poly->totloop;
+ float *weights = BLI_array_alloca(weights, coarse_poly->totloop);
+ int *indices = BLI_array_alloca(indices, coarse_poly->totloop);
+ for (int i = 0; i < coarse_poly->totloop; ++i) {
+ weights[i] = weight;
+ indices[i] = coarse_poly->loopstart + i;
+ }
+ CustomData_interp(&coarse_mesh->ldata,
+ &loop_interpolation->loop_data_storage,
+ indices,
+ weights, NULL,
+ coarse_poly->totloop,
+ 2);
+ }
+}
+
+static void loop_interpolation_from_corner(
+ const SubdivMeshContext *ctx,
+ LoopsForInterpolation *loop_interpolation,
+ const MPoly *coarse_poly,
+ const int corner)
+{
+ if (coarse_poly->totloop == 4) {
+ /* Nothing to do, all indices and data is already assigned. */
+ }
+ else {
+ const CustomData *loop_data = &ctx->coarse_mesh->ldata;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MLoop *coarse_mloop = coarse_mesh->mloop;
+ LoopsOfPtex loops_of_ptex;
+ loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, corner);
+ /* Ptex face corner corresponds to a poly loop with same index. */
+ CustomData_free_elem(&loop_interpolation->loop_data_storage, 0, 1);
+ CustomData_copy_data(loop_data,
+ &loop_interpolation->loop_data_storage,
+ coarse_poly->loopstart + corner,
+ 0,
+ 1);
+ /* Interpolate remaining ptex face corners, which hits loops
+ * middle points.
+ *
+ * TODO(sergey): Re-use one of interpolation results from previous
+ * iteration.
+ */
+ const float weights[2] = {0.5f, 0.5f};
+ const int first_indices[2] = {
+ loops_of_ptex.first_loop - coarse_mloop,
+ (loops_of_ptex.first_loop + 1 - coarse_mloop) %
+ coarse_poly->totloop};
+ const int last_indices[2] = {
+ loops_of_ptex.last_loop - coarse_mloop,
+ loops_of_ptex.first_loop - coarse_mloop};
+ CustomData_interp(loop_data,
+ &loop_interpolation->loop_data_storage,
+ first_indices,
+ weights, NULL,
+ 2,
+ 1);
+ CustomData_interp(loop_data,
+ &loop_interpolation->loop_data_storage,
+ last_indices,
+ weights, NULL,
+ 2,
+ 3);
+ }
+}
+
+static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation)
+{
+ if (loop_interpolation->loop_data_storage_allocated) {
+ CustomData_free(&loop_interpolation->loop_data_storage, 4);
+ }
+}
+
+/* =============================================================================
+ * TLS.
+ */
+
+typedef struct SubdivMeshTLS {
+ bool vertex_interpolation_initialized;
+ VerticesForInterpolation vertex_interpolation;
+ const MPoly *vertex_interpolation_coarse_poly;
+ int vertex_interpolation_coarse_corner;
+
+ bool loop_interpolation_initialized;
+ LoopsForInterpolation loop_interpolation;
+ const MPoly *loop_interpolation_coarse_poly;
+ int loop_interpolation_coarse_corner;
+} SubdivMeshTLS;
+
+static void subdiv_mesh_tls_free(void *tls_v)
+{
+ SubdivMeshTLS *tls = tls_v;
+ if (tls->vertex_interpolation_initialized) {
+ vertex_interpolation_end(&tls->vertex_interpolation);
+ }
+ if (tls->loop_interpolation_initialized) {
+ loop_interpolation_end(&tls->loop_interpolation);
+ }
+}
+
+/* =============================================================================
+ * Evaluation helper functions.
+ */
+
+static void eval_final_point_and_vertex_normal(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ float r_P[3], short r_N[3])
+{
+ if (subdiv->displacement_evaluator == NULL) {
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ subdiv, ptex_face_index, u, v, r_P, r_N);
+ }
+ else {
+ BKE_subdiv_eval_final_point(
+ subdiv, ptex_face_index, u, v, r_P);
+ }
+}
+
+/* =============================================================================
+ * Displacement helpers
+ */
+
+static void subdiv_accumulate_vertex_displacement(
+ Subdiv *subdiv,
+ const int ptex_face_index,
+ const float u, const float v,
+ MVert *subdiv_vert)
+{
+ float dummy_P[3], dPdu[3], dPdv[3], D[3];
+ BKE_subdiv_eval_limit_point_and_derivatives(
+ subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
+ BKE_subdiv_eval_displacement(subdiv,
+ ptex_face_index, u, v,
+ dPdu, dPdv,
+ D);
+ add_v3_v3(subdiv_vert->co, D);
+ if (subdiv_vert->flag & ME_VERT_TMP_TAG) {
+ mul_v3_fl(subdiv_vert->co, 0.5f);
+ }
+ subdiv_vert->flag |= ME_VERT_TMP_TAG;
+}
+
+/* =============================================================================
+ * Callbacks.
+ */
+
+static bool subdiv_mesh_topology_info(
+ const SubdivForeachContext *foreach_context,
+ const int num_vertices,
+ const int num_edges,
+ const int num_loops,
+ const int num_polygons)
+{
+ SubdivMeshContext *subdiv_context = foreach_context->user_data;
+ subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template(
+ subdiv_context->coarse_mesh,
+ num_vertices,
+ num_edges,
+ 0,
+ num_loops,
+ num_polygons);
+ subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context);
+ return true;
+}
+
+/* =============================================================================
+ * Vertex subdivision process.
+ */
+
+static void subdiv_vertex_data_copy(
+ const SubdivMeshContext *ctx,
+ const MVert *coarse_vertex,
+ MVert *subdiv_vertex)
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ const int coarse_vertex_index = coarse_vertex - coarse_mesh->mvert;
+ const int subdiv_vertex_index = subdiv_vertex - subdiv_mesh->mvert;
+ subdiv_vertex->flag &= ~ME_VERT_TMP_TAG;
+ CustomData_copy_data(&coarse_mesh->vdata,
+ &ctx->subdiv_mesh->vdata,
+ coarse_vertex_index,
+ subdiv_vertex_index,
+ 1);
+}
+
+static void subdiv_vertex_data_interpolate(
+ const SubdivMeshContext *ctx,
+ MVert *subdiv_vertex,
+ const VerticesForInterpolation *vertex_interpolation,
+ const float u, const float v)
+{
+ const int subdiv_vertex_index = subdiv_vertex - ctx->subdiv_mesh->mvert;
+ const float weights[4] = {(1.0f - u) * (1.0f - v),
+ u * (1.0f - v),
+ u * v,
+ (1.0f - u) * v};
+ subdiv_vertex->flag &= ~ME_VERT_TMP_TAG;
+ CustomData_interp(vertex_interpolation->vertex_data,
+ &ctx->subdiv_mesh->vdata,
+ vertex_interpolation->vertex_indices,
+ weights, NULL,
+ 4,
+ subdiv_vertex_index);
+ if (ctx->vert_origindex != NULL) {
+ ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE;
+ }
+}
+
+static void evaluate_vertex_and_apply_displacement_copy(
+ const SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u, const float v,
+ const MVert *coarse_vert,
+ MVert *subdiv_vert)
+{
+ /* Displacement is accumulated in subdiv vertex position.
+ * need to back it up before copying data from original vertex.
+ */
+ float D[3];
+ copy_v3_v3(D, subdiv_vert->co);
+ subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ ctx->subdiv,
+ ptex_face_index,
+ u, v,
+ subdiv_vert->co, subdiv_vert->no);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
+}
+
+static void evaluate_vertex_and_apply_displacement_interpolate(
+ const SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u, const float v,
+ VerticesForInterpolation *vertex_interpolation,
+ MVert *subdiv_vert)
+{
+ /* Displacement is accumulated in subdiv vertex position.
+ * need to back it up before copying data from original vertex.
+ */
+ float D[3];
+ copy_v3_v3(D, subdiv_vert->co);
+ subdiv_vertex_data_interpolate(ctx,
+ subdiv_vert,
+ vertex_interpolation,
+ u, v);
+ BKE_subdiv_eval_limit_point_and_short_normal(
+ ctx->subdiv,
+ ptex_face_index,
+ u, v,
+ subdiv_vert->co, subdiv_vert->no);
+ /* Apply displacement. */
+ add_v3_v3(subdiv_vert->co, D);
+}
+
+static void subdiv_mesh_vertex_every_corner_or_edge(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ Subdiv *subdiv = ctx->subdiv;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_accumulate_vertex_displacement(
+ subdiv, ptex_face_index, u, v, subdiv_vert);
+}
+
+static void subdiv_mesh_vertex_every_corner(
+ const SubdivForeachContext *foreach_context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_vertex_index),
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
+{
+ subdiv_mesh_vertex_every_corner_or_edge(
+ foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
+}
+
+static void subdiv_mesh_vertex_every_edge(
+ const SubdivForeachContext *foreach_context,
+ void *tls,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_edge_index),
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
+{
+ subdiv_mesh_vertex_every_corner_or_edge(
+ foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
+}
+
+static void subdiv_mesh_vertex_corner(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
+{
+ BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ const MVert *coarse_vert = &coarse_mvert[coarse_vertex_index];
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ evaluate_vertex_and_apply_displacement_copy(
+ ctx, ptex_face_index, u, v, coarse_vert, subdiv_vert);
+}
+
+static void subdiv_mesh_ensure_vertex_interpolation(
+ SubdivMeshContext *ctx,
+ SubdivMeshTLS *tls,
+ const MPoly *coarse_poly,
+ const int coarse_corner)
+{
+ /* Check whether we've moved to another corner or polygon. */
+ if (tls->vertex_interpolation_initialized) {
+ if (tls->vertex_interpolation_coarse_poly != coarse_poly ||
+ tls->vertex_interpolation_coarse_corner != coarse_corner)
+ {
+ vertex_interpolation_end(&tls->vertex_interpolation);
+ tls->vertex_interpolation_initialized = false;
+ }
+ }
+ /* Initialize the interpolation. */
+ if (!tls->vertex_interpolation_initialized) {
+ vertex_interpolation_init(ctx, &tls->vertex_interpolation, coarse_poly);
+ }
+ /* Update it for a new corner if needed. */
+ if (!tls->vertex_interpolation_initialized ||
+ tls->vertex_interpolation_coarse_corner != coarse_corner)
+ {
+ vertex_interpolation_from_corner(
+ ctx, &tls->vertex_interpolation, coarse_poly, coarse_corner);
+ }
+ /* Store settings used for the current state of interpolator. */
+ tls->vertex_interpolation_initialized = true;
+ tls->vertex_interpolation_coarse_poly = coarse_poly;
+ tls->vertex_interpolation_coarse_corner = coarse_corner;
+}
+
+static void subdiv_mesh_vertex_edge(
+ const SubdivForeachContext *foreach_context,
+ void *tls_v,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_edge_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ SubdivMeshTLS *tls = tls_v;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_mesh_ensure_vertex_interpolation(
+ ctx, tls, coarse_poly, coarse_corner);
+ evaluate_vertex_and_apply_displacement_interpolate(
+ ctx,
+ ptex_face_index, u, v,
+ &tls->vertex_interpolation,
+ subdiv_vert);
+}
+
+static void subdiv_mesh_vertex_inner(
+ const SubdivForeachContext *foreach_context,
+ void *tls_v,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ SubdivMeshTLS *tls = tls_v;
+ Subdiv *subdiv = ctx->subdiv;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_mesh_ensure_vertex_interpolation(
+ ctx, tls, coarse_poly, coarse_corner);
+ subdiv_vertex_data_interpolate(
+ ctx, subdiv_vert, &tls->vertex_interpolation, u, v);
+ eval_final_point_and_vertex_normal(
+ subdiv, ptex_face_index, u, v, subdiv_vert->co, subdiv_vert->no);
+}
+
+/* =============================================================================
+ * Edge subdivision process.
+ */
+
+static void subdiv_copy_edge_data(
+ SubdivMeshContext *ctx,
+ MEdge *subdiv_edge,
+ const MEdge *coarse_edge)
+{
+ const int subdiv_edge_index = subdiv_edge - ctx->subdiv_mesh->medge;
+ if (coarse_edge == NULL) {
+ subdiv_edge->crease = 0;
+ subdiv_edge->bweight = 0;
+ subdiv_edge->flag = 0;
+ if (ctx->edge_origindex != NULL) {
+ ctx->edge_origindex[subdiv_edge_index] = ORIGINDEX_NONE;
+ }
+ return;
+ }
+ const int coarse_edge_index = coarse_edge - ctx->coarse_mesh->medge;
+ CustomData_copy_data(&ctx->coarse_mesh->edata,
+ &ctx->subdiv_mesh->edata,
+ coarse_edge_index,
+ subdiv_edge_index,
+ 1);
+}
+
+static void subdiv_mesh_edge(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_edge_index,
+ const int subdiv_edge_index,
+ const int subdiv_v1, const int subdiv_v2)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MEdge *subdiv_medge = subdiv_mesh->medge;
+ MEdge *subdiv_edge = &subdiv_medge[subdiv_edge_index];
+ if (coarse_edge_index != ORIGINDEX_NONE) {
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ const MEdge *coarse_edge = &coarse_medge[coarse_edge_index];
+ subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge);
+ }
+ subdiv_edge->v1 = subdiv_v1;
+ subdiv_edge->v2 = subdiv_v2;
+}
+
+/* =============================================================================
+ * Loops creation/interpolation.
+ */
+
+static void subdiv_interpolate_loop_data(
+ const SubdivMeshContext *ctx,
+ MLoop *subdiv_loop,
+ const LoopsForInterpolation *loop_interpolation,
+ const float u, const float v)
+{
+ const int subdiv_loop_index = subdiv_loop - ctx->subdiv_mesh->mloop;
+ const float weights[4] = {(1.0f - u) * (1.0f - v),
+ u * (1.0f - v),
+ u * v,
+ (1.0f - u) * v};
+ CustomData_interp(loop_interpolation->loop_data,
+ &ctx->subdiv_mesh->ldata,
+ loop_interpolation->loop_indices,
+ weights, NULL,
+ 4,
+ subdiv_loop_index);
+ /* TODO(sergey): Set ORIGINDEX. */
+}
+
+static void subdiv_eval_uv_layer(SubdivMeshContext *ctx,
+ MLoop *subdiv_loop,
+ const int ptex_face_index,
+ const float u, const float v)
+{
+ if (ctx->num_uv_layers == 0) {
+ return;
+ }
+ Subdiv *subdiv = ctx->subdiv;
+ const int mloop_index = subdiv_loop - ctx->subdiv_mesh->mloop;
+ for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
+ MLoopUV *subdiv_loopuv = &ctx->uv_layers[layer_index][mloop_index];
+ BKE_subdiv_eval_face_varying(subdiv,
+ layer_index,
+ ptex_face_index,
+ u, v,
+ subdiv_loopuv->uv);
+ }
+}
+
+static void subdiv_mesh_ensure_loop_interpolation(
+ SubdivMeshContext *ctx,
+ SubdivMeshTLS *tls,
+ const MPoly *coarse_poly,
+ const int coarse_corner)
+{
+ /* Check whether we've moved to another corner or polygon. */
+ if (tls->loop_interpolation_initialized) {
+ if (tls->loop_interpolation_coarse_poly != coarse_poly ||
+ tls->loop_interpolation_coarse_corner != coarse_corner)
+ {
+ loop_interpolation_end(&tls->loop_interpolation);
+ tls->loop_interpolation_initialized = false;
+ }
+ }
+ /* Initialize the interpolation. */
+ if (!tls->loop_interpolation_initialized) {
+ loop_interpolation_init(ctx, &tls->loop_interpolation, coarse_poly);
+ }
+ /* Update it for a new corner if needed. */
+ if (!tls->loop_interpolation_initialized ||
+ tls->loop_interpolation_coarse_corner != coarse_corner)
+ {
+ loop_interpolation_from_corner(
+ ctx, &tls->loop_interpolation, coarse_poly, coarse_corner);
+ }
+ /* Store settings used for the current state of interpolator. */
+ tls->loop_interpolation_initialized = true;
+ tls->loop_interpolation_coarse_poly = coarse_poly;
+ tls->loop_interpolation_coarse_corner = coarse_corner;
+}
+
+static void subdiv_mesh_loop(
+ const SubdivForeachContext *foreach_context,
+ void *tls_v,
+ const int ptex_face_index,
+ const float u, const float v,
+ const int UNUSED(coarse_loop_index),
+ const int coarse_poly_index,
+ const int coarse_corner,
+ const int subdiv_loop_index,
+ const int subdiv_vertex_index, const int subdiv_edge_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ SubdivMeshTLS *tls = tls_v;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MLoop *subdiv_mloop = subdiv_mesh->mloop;
+ MLoop *subdiv_loop = &subdiv_mloop[subdiv_loop_index];
+ subdiv_mesh_ensure_loop_interpolation(
+ ctx, tls, coarse_poly, coarse_corner);
+ subdiv_interpolate_loop_data(
+ ctx, subdiv_loop, &tls->loop_interpolation, u, v);
+ subdiv_eval_uv_layer(ctx, subdiv_loop, ptex_face_index, u, v);
+ subdiv_loop->v = subdiv_vertex_index;
+ subdiv_loop->e = subdiv_edge_index;
+}
+
+/* =============================================================================
+ * Polygons subdivision process.
+ */
+
+static void subdiv_copy_poly_data(const SubdivMeshContext *ctx,
+ MPoly *subdiv_poly,
+ const MPoly *coarse_poly)
+{
+ const int coarse_poly_index = coarse_poly - ctx->coarse_mesh->mpoly;
+ const int subdiv_poly_index = subdiv_poly - ctx->subdiv_mesh->mpoly;
+ CustomData_copy_data(&ctx->coarse_mesh->pdata,
+ &ctx->subdiv_mesh->pdata,
+ coarse_poly_index,
+ subdiv_poly_index,
+ 1);
+}
+
+static void subdiv_mesh_poly(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_poly_index,
+ const int subdiv_poly_index,
+ const int start_loop_index, const int num_loops)
+{
+ BLI_assert(coarse_poly_index != ORIGINDEX_NONE);
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MPoly *coarse_mpoly = coarse_mesh->mpoly;
+ const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MPoly *subdiv_mpoly = subdiv_mesh->mpoly;
+ MPoly *subdiv_poly = &subdiv_mpoly[subdiv_poly_index];
+ subdiv_copy_poly_data(ctx, subdiv_poly, coarse_poly);
+ subdiv_poly->loopstart = start_loop_index;
+ subdiv_poly->totloop = num_loops;
+}
+
+/* =============================================================================
+ * Loose elements subdivision process.
+ */
+
+static void subdiv_mesh_vertex_loose(
+ const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_vertex_index,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ const MVert *coarse_vertex = &coarse_mvert[coarse_vertex_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
+ subdiv_vertex_data_copy(ctx, coarse_vertex, subdiv_vertex);
+}
+
+/* Get neighbor edges of the given one.
+ * - neighbors[0] is an edge adjacent to edge->v1.
+ * - neighbors[1] is an edge adjacent to edge->v1.
+ */
+static void find_edge_neighbors(const SubdivMeshContext *ctx,
+ const MEdge *edge,
+ const MEdge *neighbors[2])
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_medge = coarse_mesh->medge;
+ neighbors[0] = NULL;
+ neighbors[1] = NULL;
+ for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) {
+ const MEdge *current_edge = &coarse_medge[edge_index];
+ if (current_edge == edge) {
+ continue;
+ }
+ if (ELEM(edge->v1, current_edge->v1, current_edge->v2)) {
+ neighbors[0] = current_edge;
+ }
+ if (ELEM(edge->v2, current_edge->v1, current_edge->v2)) {
+ neighbors[1] = current_edge;
+ }
+ }
+}
+
+static void points_for_loose_edges_interpolation_get(
+ SubdivMeshContext *ctx,
+ const MEdge *coarse_edge,
+ const MEdge *neighbors[2],
+ float points_r[4][3])
+{
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MVert *coarse_mvert = coarse_mesh->mvert;
+ /* Middle points corresponds to the edge. */
+ copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co);
+ copy_v3_v3(points_r[2], coarse_mvert[coarse_edge->v2].co);
+ /* Start point, duplicate from edge start if no neighbor. */
+ if (neighbors[0] != NULL) {
+ if (neighbors[0]->v1 == coarse_edge->v1) {
+ copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v2].co);
+ }
+ else {
+ copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v1].co);
+ }
+ }
+ else {
+ sub_v3_v3v3(points_r[0], points_r[1], points_r[2]);
+ add_v3_v3(points_r[0], points_r[1]);
+ }
+ /* End point, duplicate from edge end if no neighbor. */
+ if (neighbors[1] != NULL) {
+ if (neighbors[1]->v1 == coarse_edge->v2) {
+ copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v2].co);
+ }
+ else {
+ copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v1].co);
+ }
+ }
+ else {
+ sub_v3_v3v3(points_r[3], points_r[2], points_r[1]);
+ add_v3_v3(points_r[3], points_r[2]);
+ }
+}
+
+static void subdiv_mesh_vertex_of_loose_edge(
+ const struct SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_edge_index,
+ const float u,
+ const int subdiv_vertex_index)
+{
+ SubdivMeshContext *ctx = foreach_context->user_data;
+ const Mesh *coarse_mesh = ctx->coarse_mesh;
+ const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index];
+ Mesh *subdiv_mesh = ctx->subdiv_mesh;
+ MVert *subdiv_mvert = subdiv_mesh->mvert;
+ /* Find neighbors of the current loose edge. */
+ const MEdge *neighbors[2];
+ find_edge_neighbors(ctx, coarse_edge, neighbors);
+ /* Get points for b-spline interpolation. */
+ float points[4][3];
+ points_for_loose_edges_interpolation_get(
+ ctx, coarse_edge, neighbors, points);
+ /* Perform interpolation. */
+ float weights[4];
+ key_curve_position_weights(u, weights, KEY_BSPLINE);
+
+ MVert *subdiv_vertex = &subdiv_mvert[subdiv_vertex_index];
+ interp_v3_v3v3v3v3(subdiv_vertex->co,
+ points[0],
+ points[1],
+ points[2],
+ points[3],
+ weights);
+ /* Reset flags and such. */
+ subdiv_vertex->flag = 0;
+ subdiv_vertex->bweight = 0.0f;
+ /* Reset normal. */
+ subdiv_vertex->no[0] = 0.0f;
+ subdiv_vertex->no[1] = 0.0f;
+ subdiv_vertex->no[2] = 1.0f;
+}
+
+/* =============================================================================
+ * Initialization.
+ */
+
+static void setup_foreach_callbacks(SubdivForeachContext *foreach_context,
+ const Subdiv *subdiv)
+{
+ memset(foreach_context, 0, sizeof(*foreach_context));
+ /* General information. */
+ foreach_context->topology_info = subdiv_mesh_topology_info;
+ /* Every boundary geometry. Used for dispalcement averaging. */
+ if (subdiv->displacement_evaluator != NULL) {
+ foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
+ foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge;
+ }
+ else {
+ foreach_context->vertex_every_corner = NULL;
+ foreach_context->vertex_every_edge = NULL;
+ }
+ foreach_context->vertex_corner = subdiv_mesh_vertex_corner;
+ foreach_context->vertex_edge = subdiv_mesh_vertex_edge;
+ foreach_context->vertex_inner = subdiv_mesh_vertex_inner;
+ foreach_context->edge = subdiv_mesh_edge;
+ foreach_context->loop = subdiv_mesh_loop;
+ foreach_context->poly = subdiv_mesh_poly;
+ foreach_context->vertex_loose = subdiv_mesh_vertex_loose;
+ foreach_context->vertex_of_loose_edge = subdiv_mesh_vertex_of_loose_edge;
+ foreach_context->user_data_tls_free = subdiv_mesh_tls_free;
+}
+
+/* =============================================================================
+ * Public entry point.
+ */
+
+Mesh *BKE_subdiv_to_mesh(
+ Subdiv *subdiv,
+ const SubdivToMeshSettings *settings,
+ const Mesh *coarse_mesh)
+{
+ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ /* Make sure evaluator is up to date with possible new topology, and that
+ * is is refined for the new positions of coarse vertices.
+ */
+ if (!BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh)) {
+ /* This could happen in two situations:
+ * - OpenSubdiv is disabled.
+ * - Something totally bad happened, and OpenSubdiv rejected our
+ * topology.
+ * In either way, we can't safely continue.
+ */
+ if (coarse_mesh->totpoly) {
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ return NULL;
+ }
+ }
+ /* Initialize subdivion mesh creation context/ */
+ SubdivMeshContext subdiv_context = {0};
+ subdiv_context.coarse_mesh = coarse_mesh;
+ subdiv_context.subdiv = subdiv;
+ /* Multi-threaded traversal/evaluation. */
+ BKE_subdiv_stats_begin(&subdiv->stats,
+ SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ SubdivForeachContext foreach_context;
+ setup_foreach_callbacks(&foreach_context, subdiv);
+ SubdivMeshTLS tls = {0};
+ foreach_context.user_data = &subdiv_context;
+ foreach_context.user_data_tls_size = sizeof(SubdivMeshTLS);
+ foreach_context.user_data_tls = &tls;
+ BKE_subdiv_foreach_subdiv_geometry(subdiv,
+ &foreach_context,
+ settings,
+ coarse_mesh);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
+ Mesh *result = subdiv_context.subdiv_mesh;
+ // BKE_mesh_validate(result, true, true);
+ BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
+ if (subdiv->displacement_evaluator != NULL) {
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/subdiv_stats.c b/source/blender/blenkernel/intern/subdiv_stats.c
new file mode 100644
index 00000000000..a0cd1d909b7
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_stats.c
@@ -0,0 +1,92 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/subdiv_stats.c
+ * \ingroup bke
+ */
+
+#include "BKE_subdiv.h"
+
+#include <stdio.h>
+
+#include "PIL_time.h"
+
+void BKE_subdiv_stats_init(SubdivStats *stats)
+{
+ stats->topology_refiner_creation_time = 0.0;
+ stats->subdiv_to_mesh_time = 0.0;
+ stats->subdiv_to_mesh_geometry_time = 0.0;
+ stats->evaluator_creation_time = 0.0;
+ stats->evaluator_refine_time = 0.0;
+ stats->subdiv_to_ccg_time = 0.0;
+ stats->subdiv_to_ccg_elements_time = 0.0;
+}
+
+void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value)
+{
+ stats->begin_timestamp_[value] = PIL_check_seconds_timer();
+}
+
+void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value)
+{
+ stats->values_[value] =
+ PIL_check_seconds_timer() - stats->begin_timestamp_[value];
+}
+
+void BKE_subdiv_stats_print(const SubdivStats *stats)
+{
+#define STATS_PRINT_TIME(stats, value, description) \
+ do { \
+ if ((stats)->value > 0.0) { \
+ printf(" %s: %f (sec)\n", description, (stats)->value); \
+ } \
+ } while (false)
+
+ printf("Subdivision surface statistics:\n");
+
+ STATS_PRINT_TIME(stats,
+ topology_refiner_creation_time,
+ "Topology refiner creation time");
+ STATS_PRINT_TIME(stats,
+ subdiv_to_mesh_time,
+ "Subdivision to mesh time");
+ STATS_PRINT_TIME(stats,
+ subdiv_to_mesh_geometry_time,
+ " Geometry time");
+ STATS_PRINT_TIME(stats,
+ evaluator_creation_time,
+ "Evaluator creation time");
+ STATS_PRINT_TIME(stats,
+ evaluator_refine_time,
+ "Evaluator refine time");
+ STATS_PRINT_TIME(stats,
+ subdiv_to_ccg_time,
+ "Subdivision to CCG time");
+ STATS_PRINT_TIME(stats,
+ subdiv_to_ccg_elements_time,
+ " Elements time");
+
+#undef STATS_PRINT_TIME
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 3c4e1f92344..bba3e97cad7 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -69,6 +69,7 @@
#include "BKE_mesh_mapping.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
@@ -77,12 +78,6 @@
# include "BLI_array.h"
#endif
-#include "GPU_draw.h"
-#include "GPU_glew.h"
-#include "GPU_buffers.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
#include "CCGSubSurf.h"
#ifdef WITH_OPENSUBDIV
@@ -1050,43 +1045,6 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
int gridSideEdges;
int gridInternalEdges;
- /* code added in bmesh but works correctly without, commenting - campbell */
-#if 0
- int lasti, previ;
- i = lastface;
- lasti = 0;
- while (1) {
- previ = i;
- if (ccgdm->faceMap[i].startEdge >= edgeNum) {
- i -= fabsf(i - lasti) / 2.0f;
- }
- else if (ccgdm->faceMap[i].startEdge < edgeNum) {
- i += fabsf(i - lasti) / 2.0f;
- }
- else {
- break;
- }
-
- if (i < 0) {
- i = 0;
- break;
- }
-
- if (i > lastface) {
- i = lastface;
- break;
-
- }
-
- if (i == lasti)
- break;
-
- lasti = previ;
- }
-
- i = i > 0 ? i - 1 : i;
-#endif
-
i = 0;
while (i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge) {
i++;
@@ -1766,47 +1724,7 @@ static void ccgDM_foreachMappedLoop(
}
}
-static void ccgDM_drawVerts(DerivedMesh *dm)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- CCGVertIterator vi;
- CCGEdgeIterator ei;
- CCGFaceIterator fi;
-
- glBegin(GL_POINTS);
- for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
- CCGVert *v = ccgVertIterator_getCurrent(&vi);
- glVertex3fv(ccgSubSurf_getVertData(ss, v));
- }
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- int x;
-
- for (x = 1; x < edgeSize - 1; x++)
- glVertex3fv(ccgSubSurf_getEdgeData(ss, e, x));
- }
-
- for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
- CCGFace *f = ccgFaceIterator_getCurrent(&fi);
- int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- glVertex3fv(ccgSubSurf_getFaceCenterData(f));
- for (S = 0; S < numVerts; S++)
- for (x = 1; x < gridSize - 1; x++)
- glVertex3fv(ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
- for (S = 0; S < numVerts; S++)
- for (y = 1; y < gridSize - 1; y++)
- for (x = 1; x < gridSize - 1; x++)
- glVertex3fv(ccgSubSurf_getFaceGridData(ss, f, S, x, y));
- }
- glEnd();
-}
-
-static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
+static void UNUSED_FUNCTION(ccgdm_pbvh_update)(CCGDerivedMesh *ccgdm)
{
if (ccgdm->pbvh && ccgDM_use_grid_pbvh(ccgdm)) {
CCGFace **faces;
@@ -1821,2179 +1739,6 @@ static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
}
}
-static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
-{
- GPUDrawObject *gdo;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- /* TODO(sergey): We currently only support all edges drawing. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
- ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
- }
- return;
- }
-#endif
-
- ccgdm_pbvh_update(ccgdm);
-
-/* old debug feature for edges, unsupported for now */
-#if 0
- int useAging = 0;
-
- if (!(G.f & G_BACKBUFSEL)) {
- CCGSubSurf *ss = ccgdm->ss;
- ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
- /* it needs some way to upload this to VBO now */
- if (useAging) {
- int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
- glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
- }
- }
-#endif
-
- GPU_edge_setup(dm);
- gdo = dm->drawObject;
- if (gdo->edges && gdo->points) {
- if (drawAllEdges && drawLooseEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, (gdo->totedge - gdo->totinterior) * 2);
- }
- else if (drawAllEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2);
- }
- else {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2);
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, gdo->tot_loose_edge_drawn * 2);
- }
- }
-
- if (gdo->edges && ccgdm->drawInteriorEdges) {
- GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->interior_offset * 2, gdo->totinterior * 2);
- }
- GPU_buffers_unbind();
-}
-
-static void ccgDM_drawLooseEdges(DerivedMesh *dm)
-{
- int start;
- int count;
-
-#ifdef WITH_OPENSUBDIV
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- if (ccgdm->useGpuBackend) {
- /* TODO(sergey): Needs implementation. */
- return;
- }
-#endif
-
- GPU_edge_setup(dm);
-
- start = (dm->drawObject->loose_edge_offset * 2);
- count = (dm->drawObject->interior_offset - dm->drawObject->loose_edge_offset) * 2;
-
- if (count) {
- GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count);
- }
-
- GPU_buffers_unbind();
-}
-
-static void ccgDM_NormalFast(float *a, float *b, float *c, float *d, float no[3])
-{
- float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
- float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
-
- no[0] = b_dY * a_cZ - b_dZ * a_cY;
- no[1] = b_dZ * a_cX - b_dX * a_cZ;
- no[2] = b_dX * a_cY - b_dY * a_cX;
-
- normalize_v3(no);
-}
-
-
-static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
-{
- float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
- float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
- float no[3];
-
- no[0] = b_dY * a_cZ - b_dZ * a_cY;
- no[1] = b_dZ * a_cX - b_dX * a_cZ;
- no[2] = b_dX * a_cY - b_dY * a_cX;
-
- /* don't normalize, GL_NORMALIZE is enabled */
- glNormal3fv(no);
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_normal(
- DerivedMesh *dm, short *varray)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int shademodel;
- int start = 0;
-
- /* we are in sculpt mode, disable loop normals (since they won't get updated) */
- if (ccgdm->pbvh)
- lnors = NULL;
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- const float (*ln)[3] = NULL;
-
- if (faceFlags) {
- shademodel = (lnors || (faceFlags[index].flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT;
- }
- else {
- shademodel = GL_SMOOTH;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += gridFaces * gridFaces * numVerts * 4;
- }
-
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
-
- if (ln) {
- /* Can't use quad strips here... */
- for (y = 0; y < gridFaces; y ++) {
- for (x = 0; x < gridFaces; x ++) {
- normal_float_to_short_v3(&varray[start + 0], ln[0]);
- normal_float_to_short_v3(&varray[start + 4], ln[3]);
- normal_float_to_short_v3(&varray[start + 8], ln[2]);
- normal_float_to_short_v3(&varray[start + 12], ln[1]);
-
- start += 16;
- ln += 4;
- }
- }
- }
- else if (shademodel == GL_SMOOTH) {
- for (y = 0; y < gridFaces; y ++) {
- for (x = 0; x < gridFaces; x ++) {
- float *a = CCG_grid_elem_no(&key, faceGridData, x, y );
- float *b = CCG_grid_elem_no(&key, faceGridData, x + 1, y);
- float *c = CCG_grid_elem_no(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_no(&key, faceGridData, x, y + 1);
-
- normal_float_to_short_v3(&varray[start], a);
- normal_float_to_short_v3(&varray[start + 4], b);
- normal_float_to_short_v3(&varray[start + 8], c);
- normal_float_to_short_v3(&varray[start + 12], d);
-
- start += 16;
- }
- }
- }
- else {
- for (y = 0; y < gridFaces; y ++) {
- for (x = 0; x < gridFaces; x ++) {
- float f_no[3];
- short f_no_s[3];
-
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y );
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y );
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_NormalFast(a, b, c, d, f_no);
- normal_float_to_short_v3(f_no_s, f_no);
-
- copy_v3_v3_short(&varray[start], f_no_s);
- copy_v3_v3_short(&varray[start + 4], f_no_s);
- copy_v3_v3_short(&varray[start + 8], f_no_s);
- copy_v3_v3_short(&varray[start + 12], f_no_s);
-
- start += 16;
- }
- }
- }
- }
- }
-}
-
-typedef struct FaceCount {
- unsigned int i_visible;
- unsigned int i_hidden;
- unsigned int i_tri_visible;
- unsigned int i_tri_hidden;
-} FaceCount;
-
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_triangles(
- DerivedMesh *dm, unsigned int *varray,
- const int *mat_orig_to_new)
-{
- GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials;
- const int gpu_totmat = dm->drawObject->totmaterial;
- const short dm_totmat = dm->totmat;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- short mat_nr = -1;
- int start;
- int totloops = 0;
- FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount");
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < gpu_totmat; i++) {
- fc[i].i_visible = 0;
- fc[i].i_tri_visible = 0;
- fc[i].i_hidden = gpumaterials[i].totpolys - 1;
- fc[i].i_tri_hidden = gpumaterials[i].totelements - 1;
- }
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- bool is_hidden;
- int mati;
-
- if (faceFlags) {
- mat_nr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat);
- is_hidden = (faceFlags[index].flag & ME_HIDE) != 0;
- }
- else {
- mat_nr = 0;
- is_hidden = false;
- }
- mati = mat_orig_to_new[mat_nr];
- gpumat = dm->drawObject->materials + mati;
-
- if (is_hidden) {
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- start = gpumat->start + fc[mati].i_tri_hidden;
-
- varray[start--] = totloops;
- varray[start--] = totloops + 2;
- varray[start--] = totloops + 3;
-
- varray[start--] = totloops;
- varray[start--] = totloops + 1;
- varray[start--] = totloops + 2;
-
- fc[mati].i_tri_hidden -= 6;
-
- totloops += 4;
- }
- }
- }
- gpumat->polys[fc[mati].i_hidden--] = i;
- }
- else {
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- start = gpumat->start + fc[mati].i_tri_visible;
-
- varray[start++] = totloops + 3;
- varray[start++] = totloops + 2;
- varray[start++] = totloops;
-
- varray[start++] = totloops + 2;
- varray[start++] = totloops + 1;
- varray[start++] = totloops;
-
- fc[mati].i_tri_visible += 6;
-
- totloops += 4;
- }
- }
- }
- gpumat->polys[fc[mati].i_visible++] = i;
- }
- }
-
- /* set the visible polygons */
- for (i = 0; i < gpu_totmat; i++) {
- gpumaterials[i].totvisiblepolys = fc[i].i_visible;
- }
-
- MEM_freeN(fc);
-}
-
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_vertex(
- DerivedMesh *dm, void *varray_p)
-{
- float *varray = varray_p;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int totedge = ccgSubSurf_getNumEdges(ss);
- int start = 0;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- copy_v3_v3(&varray[start], a);
- copy_v3_v3(&varray[start + 3], b);
- copy_v3_v3(&varray[start + 6], c);
- copy_v3_v3(&varray[start + 9], d);
-
- start += 12;
- }
- }
- }
- }
-
- /* upload loose points */
- for (i = 0; i < totedge; i++) {
- CCGEdge *e = ccgdm->edgeMap[i].edge;
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
-
- if (!ccgSubSurf_getEdgeNumFaces(e)) {
- int j = 0;
- for (j = 0; j < edgeSize; j++) {
- copy_v3_v3(&varray[start], CCG_elem_offset_co(&key, edgeData, j));
- start += 3;
- }
- }
- }
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_color(
- DerivedMesh *dm, unsigned char *varray,
- const void *user_data)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- const unsigned char *mloopcol = user_data;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int start = 0;
- int iface = 0;
-
- CCG_key_top_level(&key, ss);
-
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- copy_v4_v4_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]);
- copy_v4_v4_uchar(&varray[start + 4], &mloopcol[iface * 16 + 12]);
- copy_v4_v4_uchar(&varray[start + 8], &mloopcol[iface * 16 + 8]);
- copy_v4_v4_uchar(&varray[start + 12], &mloopcol[iface * 16 + 4]);
-
- start += 16;
- iface++;
- }
- }
- }
- }
-}
-
-static void ccgDM_buffer_copy_uv(
- DerivedMesh *dm, void *varray_p)
-{
- float *varray = varray_p;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- MLoopUV *mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int start = 0;
-
- CCG_key_top_level(&key, ss);
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- copy_v2_v2(&varray[start + 0], mloopuv[0].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[3].uv);
- copy_v2_v2(&varray[start + 4], mloopuv[2].uv);
- copy_v2_v2(&varray[start + 6], mloopuv[1].uv);
-
- mloopuv += 4;
- start += 8;
- }
- }
- }
- }
-}
-
-static void ccgDM_buffer_copy_uv_texpaint(
- DerivedMesh *dm, float *varray)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int i, totface = ccgSubSurf_getNumFaces(ss);
- int start = 0;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int dm_totmat = dm->totmat;
- MLoopUV **mloopuv_base;
- MLoopUV *stencil_base;
- int stencil;
-
- CCG_key_top_level(&key, ss);
-
- /* should have been checked for before, reassert */
- BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV));
- mloopuv_base = MEM_mallocN(dm_totmat * sizeof(*mloopuv_base), "texslots");
-
- for (i = 0; i < dm_totmat; i++) {
- mloopuv_base[i] = DM_paint_uvlayer_active_get(dm, i);
- }
-
- stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV);
- stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil);
-
- start = 0;
-
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int matnr;
-
- if (faceFlags) {
- matnr = faceFlags[index].mat_nr;
- }
- else {
- matnr = 0;
- }
-
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- /* divide by 4, gives us current loop-index */
- unsigned int i_ml = start / 4;
- copy_v2_v2(&varray[start + 0], mloopuv_base[matnr][i_ml + 0].uv);
- copy_v2_v2(&varray[start + 2], stencil_base[i_ml + 0].uv);
- copy_v2_v2(&varray[start + 4], mloopuv_base[matnr][i_ml + 3].uv);
- copy_v2_v2(&varray[start + 6], stencil_base[i_ml + 3].uv);
- copy_v2_v2(&varray[start + 8], mloopuv_base[matnr][i_ml + 2].uv);
- copy_v2_v2(&varray[start + 10], stencil_base[i_ml + 2].uv);
- copy_v2_v2(&varray[start + 12], mloopuv_base[matnr][i_ml + 1].uv);
- copy_v2_v2(&varray[start + 14], stencil_base[i_ml + 1].uv);
- start += 16;
- }
- }
- }
- }
-
- MEM_freeN(mloopuv_base);
-}
-
-static void ccgDM_buffer_copy_uvedge(
- DerivedMesh *dm, float *varray)
-{
- int i, totpoly;
- int start;
- const MLoopUV *mloopuv;
-#ifndef USE_LOOP_LAYOUT_FAST
- const MPoly *mpoly = dm->getPolyArray(dm);
-#endif
-
- if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
- return;
- }
-
- totpoly = dm->getNumPolys(dm);
- start = 0;
-
-#ifndef USE_LOOP_LAYOUT_FAST
- for (i = 0; i < totpoly; i++, mpoly++) {
- for (j = 0; j < mpoly->totloop; j++) {
- copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv);
- start += 4;
- }
- }
-#else
- for (i = 0; i < totpoly; i++) {
- copy_v2_v2(&varray[start + 0], mloopuv[(i * 4) + 0].uv);
- copy_v2_v2(&varray[start + 2], mloopuv[(i * 4) + 1].uv);
-
- copy_v2_v2(&varray[start + 4], mloopuv[(i * 4) + 1].uv);
- copy_v2_v2(&varray[start + 6], mloopuv[(i * 4) + 2].uv);
-
- copy_v2_v2(&varray[start + 8], mloopuv[(i * 4) + 2].uv);
- copy_v2_v2(&varray[start + 10], mloopuv[(i * 4) + 3].uv);
-
- copy_v2_v2(&varray[start + 12], mloopuv[(i * 4) + 3].uv);
- copy_v2_v2(&varray[start + 14], mloopuv[(i * 4) + 0].uv);
-
- start += 16;
- }
-#endif
-}
-
-static void ccgDM_buffer_copy_edge(
- DerivedMesh *dm, unsigned int *varray)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- /* getEdgeSuze returns num of verts, edges is one less */
- int i, j, edgeSize = ccgSubSurf_getEdgeSize(ss) - 1;
- int totedge = ccgSubSurf_getNumEdges(ss);
- int grid_face_side = ccgSubSurf_getGridSize(ss) - 1;
- int totface = ccgSubSurf_getNumFaces(ss);
- unsigned int index_start;
- unsigned int tot_interior = 0;
- unsigned int grid_tot_face = grid_face_side * grid_face_side;
-
- unsigned int iloose, inorm, iloosehidden, inormhidden;
- unsigned int tot_loose_hidden = 0, tot_loose = 0;
- unsigned int tot_hidden = 0, tot = 0;
- unsigned int iloosevert;
- /* int tot_interior = 0; */
-
- /* first, handle hidden/loose existing edges, then interior edges */
- for (j = 0; j < totedge; j++) {
- CCGEdge *e = ccgdm->edgeMap[j].edge;
-
- if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) {
- if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose_hidden++;
- else tot_hidden++;
- }
- else {
- if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose++;
- else tot++;
- }
- }
-
- inorm = 0;
- inormhidden = tot * edgeSize;
- iloose = (tot + tot_hidden) * edgeSize;
- iloosehidden = (tot + tot_hidden + tot_loose) * edgeSize;
- iloosevert = dm->drawObject->tot_loop_verts;
-
- /* part one, handle all normal edges */
- for (j = 0; j < totedge; j++) {
- CCGFace *f;
- int fhandle = 0;
- int totvert = 0;
- unsigned int S = 0;
- CCGEdge *e = ccgdm->edgeMap[j].edge;
- bool isloose = !ccgSubSurf_getEdgeNumFaces(e);
-
- if (!isloose) {
- CCGVert *v1, *v2;
- CCGVert *ev1 = ccgSubSurf_getEdgeVert0(e);
- CCGVert *ev2 = ccgSubSurf_getEdgeVert1(e);
-
- f = ccgSubSurf_getEdgeFace(e, 0);
- fhandle = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- totvert = ccgSubSurf_getFaceNumVerts(f);
-
- /* find the index of vertices in the face */
- for (i = 0; i < totvert; i++) {
- v1 = ccgSubSurf_getFaceVert(f, i);
- v2 = ccgSubSurf_getFaceVert(f, (i + 1) % totvert);
-
- if ((ev1 == v1 && ev2 == v2) || (ev1 == v2 && ev2 == v1)) {
- S = i;
- break;
- }
- }
- }
-
- if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) {
- if (isloose) {
- for (i = 0; i < edgeSize; i++) {
- varray[iloosehidden * 2] = iloosevert;
- varray[iloosehidden * 2 + 1] = iloosevert + 1;
- iloosehidden++;
- iloosevert++;
- }
- /* we are through with this loose edge and moving to the next, so increase by one */
- iloosevert++;
- }
- else {
- index_start = ccgdm->faceMap[fhandle].startFace;
-
- for (i = 0; i < grid_face_side; i++) {
- varray[inormhidden * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1;
- varray[inormhidden * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2;
- varray[inormhidden * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2;
- varray[inormhidden * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3;
- inormhidden += 2;
- }
- }
- }
- else {
- if (isloose) {
- for (i = 0; i < edgeSize; i++) {
- varray[iloose * 2] = iloosevert;
- varray[iloose * 2 + 1] = iloosevert + 1;
- iloose++;
- iloosevert++;
- }
- /* we are through with this loose edge and moving to the next, so increase by one */
- iloosevert++;
- }
- else {
- index_start = ccgdm->faceMap[fhandle].startFace;
-
- for (i = 0; i < grid_face_side; i++) {
- varray[inorm * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1;
- varray[inorm * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2;
- varray[inorm * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2;
- varray[inorm * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3;
- inorm += 2;
- }
- }
- }
- }
-
- /* part two, handle interior edges */
- inorm = totedge * grid_face_side * 2;
-
- index_start = 0;
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- unsigned int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- for (S = 0; S < numVerts; S++) {
- for (x = 1; x < grid_face_side; x++) {
- for (y = 0; y < grid_face_side; y++) {
- unsigned int tmp = (index_start + x * grid_face_side + y) * 4;
- varray[inorm * 2] = tmp;
- varray[inorm * 2 + 1] = tmp + 1;
- inorm++;
- }
- }
- for (x = 0; x < grid_face_side; x++) {
- for (y = 0; y < grid_face_side; y++) {
- unsigned int tmp = (index_start + x * grid_face_side + y) * 4;
- varray[inorm * 2] = tmp + 3;
- varray[inorm * 2 + 1] = tmp;
- inorm++;
- }
- }
-
- tot_interior += grid_face_side * (2 * grid_face_side - 1);
- index_start += grid_tot_face;
- }
- }
-
- dm->drawObject->tot_loose_edge_drawn = tot_loose * edgeSize;
- dm->drawObject->loose_edge_offset = (tot + tot_hidden) * edgeSize;
- dm->drawObject->tot_edge_drawn = tot * edgeSize;
-
- dm->drawObject->interior_offset = totedge * edgeSize;
- dm->drawObject->totinterior = tot_interior;
-}
-
-static void ccgDM_copy_gpu_data(
- DerivedMesh *dm, int type, void *varray_p,
- const int *mat_orig_to_new, const void *user_data)
-{
- /* 'varray_p' cast is redundant but include for self-documentation */
- switch (type) {
- case GPU_BUFFER_VERTEX:
- ccgDM_buffer_copy_vertex(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_NORMAL:
- ccgDM_buffer_copy_normal(dm, (short *)varray_p);
- break;
- case GPU_BUFFER_UV:
- ccgDM_buffer_copy_uv(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_UV_TEXPAINT:
- ccgDM_buffer_copy_uv_texpaint(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_COLOR:
- ccgDM_buffer_copy_color(dm, (unsigned char *)varray_p, user_data);
- break;
- case GPU_BUFFER_UVEDGE:
- ccgDM_buffer_copy_uvedge(dm, (float *)varray_p);
- break;
- case GPU_BUFFER_EDGE:
- ccgDM_buffer_copy_edge(dm, (unsigned int *)varray_p);
- break;
- case GPU_BUFFER_TRIANGLES:
- ccgDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new);
- break;
- default:
- break;
- }
-}
-
-static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- GPUDrawObject *gdo;
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
- const short dm_totmat = (faceFlags) ? dm->totmat : 1;
- GPUBufferMaterial *matinfo;
- int i;
- unsigned int tot_internal_edges = 0;
- int edgeVerts = ccgSubSurf_getEdgeSize(ss);
- int edgeSize = edgeVerts - 1;
-
- int totedge = ccgSubSurf_getNumEdges(ss);
- int totface = ccgSubSurf_getNumFaces(ss);
-
- /* object contains at least one material (default included) so zero means uninitialized dm */
- BLI_assert(dm_totmat != 0);
-
- matinfo = MEM_callocN(sizeof(*matinfo) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new");
-
- if (faceFlags) {
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- const short new_matnr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat);
- matinfo[new_matnr].totelements += numVerts * gridFaces * gridFaces * 6;
- matinfo[new_matnr].totloops += numVerts * gridFaces * gridFaces * 4;
- matinfo[new_matnr].totpolys++;
- tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1);
- }
- }
- else {
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- matinfo[0].totelements += numVerts * gridFaces * gridFaces * 6;
- matinfo[0].totloops += numVerts * gridFaces * gridFaces * 4;
- matinfo[0].totpolys++;
- tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1);
- }
- }
-
- /* create the GPUDrawObject */
- gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
- gdo->totvert = 0; /* used to count indices, doesn't really matter for ccgsubsurf */
- gdo->totedge = (totedge * edgeSize + tot_internal_edges);
-
- GPU_buffer_material_finalize(gdo, matinfo, dm_totmat);
-
- /* store total number of points used for triangles */
- gdo->tot_triangle_point = ccgSubSurf_getNumFinalFaces(ss) * 6;
- gdo->tot_loop_verts = ccgSubSurf_getNumFinalFaces(ss) * 4;
-
- /* finally, count loose points */
- for (i = 0; i < totedge; i++) {
- CCGEdge *e = ccgdm->edgeMap[i].edge;
-
- if (!ccgSubSurf_getEdgeNumFaces(e))
- gdo->tot_loose_point += edgeVerts;
- }
-
- return gdo;
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], bool fast, DMSetMaterial setMaterial)
-{
- int a;
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-
- ccgdm_pbvh_update(ccgdm);
-
- if (ccgdm->pbvh && ccgdm->multires.mmd) {
- if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
- BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
- setMaterial, false, fast);
- }
-
- return;
- }
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- CCGSubSurf *ss = ccgdm->ss;
- const DMFlagMat *faceFlags = ccgdm->faceFlags;
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int i, current_patch = 0;
- int mat_nr = -1;
- bool draw_smooth = false;
- int start_draw_patch = -1, num_draw_patches = 0;
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) {
- return;
- }
- if (setMaterial == NULL) {
- ccgSubSurf_drawGLMesh(ss,
- true,
- -1,
- -1);
- return;
- }
- for (i = 0; i < num_base_faces; ++i) {
- const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
- const int num_patches = (num_face_verts == 4) ? face_patches
- : num_face_verts * grid_patches;
- int new_matnr;
- bool new_draw_smooth;
- if (faceFlags) {
- new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- new_matnr = (faceFlags[i].mat_nr + 1);
- }
- else {
- new_draw_smooth = true;
- new_matnr = 1;
- }
- if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, NULL);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- start_draw_patch = current_patch;
- num_draw_patches = num_patches;
- mat_nr = new_matnr;
- draw_smooth = new_draw_smooth;
- }
- else {
- num_draw_patches += num_patches;
- }
- current_patch += num_patches;
- }
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, NULL);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- for (a = 0; a < dm->drawObject->totmaterial; a++) {
- if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start,
- dm->drawObject->materials[a].totelements);
- }
- }
- GPU_buffers_unbind();
-}
-
-typedef struct {
- DMVertexAttribs attribs;
- int numdata;
-
- GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/
-} GPUMaterialConv;
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
- DMSetMaterial setMaterial,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- GPUVertexAttribs gattribs;
- int a, b;
- const DMFlagMat *faceFlags = ccgdm->faceFlags;
- unsigned char *varray;
- size_t max_element_size = 0;
- int tot_loops = 0;
- int totpoly = ccgSubSurf_getNumFaces(ss);
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int i, current_patch = 0;
- int mat_nr = -1;
- bool draw_smooth = false;
- int start_draw_patch = -1, num_draw_patches = 0;
- GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) {
- return;
- }
- for (i = 0; i < num_base_faces; ++i) {
- const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
- const int num_patches = (num_face_verts == 4) ? face_patches
- : num_face_verts * grid_patches;
- int new_matnr;
- bool new_draw_smooth;
-
- if (faceFlags) {
- new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- new_matnr = (faceFlags[i].mat_nr + 1);
- }
- else {
- new_draw_smooth = true;
- new_matnr = 1;
- }
- if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, &gattribs);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- start_draw_patch = current_patch;
- num_draw_patches = num_patches;
- mat_nr = new_matnr;
- draw_smooth = new_draw_smooth;
- }
- else {
- num_draw_patches += num_patches;
- }
- current_patch += num_patches;
- }
- if (num_draw_patches != 0) {
- bool do_draw = setMaterial(mat_nr, &gattribs);
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
- if (setDrawOptions != NULL) {
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- DMVertexAttribs attribs = {{{NULL}}};
- int i;
- int matnr = -1;
- int do_draw = 0;
-
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
- DM_draw_attrib_vertex_uniforms(&attribs); \
-} (void)0
-
- totpoly = ccgSubSurf_getNumFaces(ss);
- for (a = 0, i = 0; i < totpoly; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- const float (*ln)[3] = NULL;
- int S, x, y, drawSmooth;
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int origIndex = ccgDM_getFaceMapIndex(ss, f);
-
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int new_matnr;
-
- if (faceFlags) {
- drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
- new_matnr = faceFlags[index].mat_nr + 1;
- }
- else {
- drawSmooth = 1;
- new_matnr = 1;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
-
- if (new_matnr != matnr) {
- do_draw = setMaterial(matnr = new_matnr, &gattribs);
- if (do_draw)
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- }
-
- if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) &&
- (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP)))
- {
- a += gridFaces * gridFaces * numVerts;
- continue;
- }
-
- glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- CCGElem *vda, *vdb;
-
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(ln[1]);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glNormal3fv(ln[2]);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glNormal3fv(ln[3]);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glNormal3fv(ln[0]);
- glVertex3fv(aco);
-
- ln += 4;
- a++;
- }
- }
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 0);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- if (x != gridFaces - 1)
- a++;
- }
-
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 3);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 2);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- glEnd();
-
- a++;
- }
- }
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_glNormalFast(aco, bco, cco, dco);
-
- PASSATTRIB(0, 1, 1);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glVertex3fv(aco);
-
- a++;
- }
- }
- glEnd();
- }
- }
- }
-
- glShadeModel(GL_SMOOTH);
-#undef PASSATTRIB
- }
- else {
- GPUMaterialConv *matconv;
- size_t offset;
- int *mat_orig_to_new;
- int tot_active_mat;
- GPUBuffer *buffer = NULL;
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
-
- tot_active_mat = dm->drawObject->totmaterial;
-
- matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat,
- "cdDM_drawMappedFacesGLSL.matconv");
- mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
- "cdDM_drawMappedFacesGLSL.mat_orig_to_new");
-
- /* part one, check what attributes are needed per material */
- for (a = 0; a < tot_active_mat; a++) {
- int new_matnr;
- int do_draw;
-
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- /* map from original material index to new
- * GPUBufferMaterial index */
- mat_orig_to_new[new_matnr] = a;
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- int numdata = 0;
- DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs);
-
- if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
- matconv[a].datatypes[numdata].size = 3;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- for (b = 0; b < matconv[a].attribs.tottface; b++) {
- if (matconv[a].attribs.tface[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 2;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.totmcol; b++) {
- if (matconv[a].attribs.mcol[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
- numdata++;
- }
- }
- for (b = 0; b < matconv[a].attribs.tottang; b++) {
- if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
- matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
- matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
- matconv[a].datatypes[numdata].size = 4;
- matconv[a].datatypes[numdata].type = GL_FLOAT;
- numdata++;
- }
- }
- if (numdata != 0) {
- matconv[a].numdata = numdata;
- max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size);
- }
- }
- }
-
- /* part two, generate and fill the arrays with the data */
- if (max_element_size > 0) {
- buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts);
-
- varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY);
- if (varray == NULL) {
- GPU_buffers_unbind();
- GPU_buffer_free(buffer);
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- fprintf(stderr, "Out of memory, can't draw object\n");
- return;
- }
-
- for (a = 0; a < totpoly; a++) {
- CCGFace *f = ccgdm->faceMap[a].face;
- int orig_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int i;
-
- if (faceFlags) {
- i = mat_orig_to_new[faceFlags[orig_index].mat_nr];
- }
- else {
- i = mat_orig_to_new[0];
- }
-
- if (matconv[i].numdata != 0) {
- for (S = 0; S < numVerts; S++) {
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
-
- offset = tot_loops * max_element_size;
-
- if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) {
- int index;
-
- index = getFaceIndex(ss, f, S, x, y, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset],
- (float *)matconv[i].attribs.orco.array[index]);
- index = getFaceIndex(ss, f, S, x + 1, y, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset + max_element_size],
- (float *)matconv[i].attribs.orco.array[index]);
- index = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset + 2 * max_element_size],
- (float *)matconv[i].attribs.orco.array[index]);
- index = getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize);
- copy_v3_v3((float *)&varray[offset + 3 * max_element_size],
- (float *)matconv[i].attribs.orco.array[index]);
-
- offset += sizeof(float) * 3;
- }
- for (b = 0; b < matconv[i].attribs.tottface; b++) {
- if (matconv[i].attribs.tface[b].array) {
- const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array + tot_loops;
-
- copy_v2_v2((float *)&varray[offset], mloopuv[0].uv);
- copy_v2_v2((float *)&varray[offset + max_element_size], mloopuv[3].uv);
- copy_v2_v2((float *)&varray[offset + 2 * max_element_size], mloopuv[2].uv);
- copy_v2_v2((float *)&varray[offset + 3 * max_element_size], mloopuv[1].uv);
-
- offset += sizeof(float) * 2;
- }
- }
- for (b = 0; b < matconv[i].attribs.totmcol; b++) {
- if (matconv[i].attribs.mcol[b].array) {
- const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array + tot_loops;
-
- copy_v4_v4_uchar(&varray[offset], &mloopcol[0].r);
- copy_v4_v4_uchar(&varray[offset + max_element_size], &mloopcol[3].r);
- copy_v4_v4_uchar(&varray[offset + 2 * max_element_size], &mloopcol[2].r);
- copy_v4_v4_uchar(&varray[offset + 3 * max_element_size], &mloopcol[1].r);
-
- offset += sizeof(unsigned char) * 4;
- }
- }
- for (b = 0; b < matconv[i].attribs.tottang; b++) {
- if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
- const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array + tot_loops;
-
- copy_v4_v4((float *)&varray[offset], looptang[0]);
- copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
- copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
- copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
-
- offset += sizeof(float) * 4;
- }
- }
-
- tot_loops += 4;
- }
- }
- }
- }
- else {
- tot_loops += 4 * numVerts * gridFaces * gridFaces;
- }
- }
- GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY);
- }
-
- for (a = 0; a < tot_active_mat; a++) {
- int new_matnr;
- int do_draw;
-
- new_matnr = dm->drawObject->materials[a].mat_nr;
-
- do_draw = setMaterial(new_matnr + 1, &gattribs);
-
- if (do_draw) {
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size);
- }
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES,
- dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
- if (matconv[a].numdata) {
- GPU_interleaved_attrib_unbind();
- }
- }
- }
-
- GPU_buffers_unbind();
- if (buffer)
- GPU_buffer_free(buffer);
-
- MEM_freeN(mat_orig_to_new);
- MEM_freeN(matconv);
- }
-}
-
-static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
-{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
- void (*setMaterial)(void *userData, int matnr, void *attribs),
- bool (*setFace)(void *userData, int index), void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- GPUVertexAttribs gattribs;
- DMVertexAttribs attribs = {{{NULL}}};
- int gridSize = ccgSubSurf_getGridSize(ss);
- int gridFaces = gridSize - 1;
- int edgeSize = ccgSubSurf_getEdgeSize(ss);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int a, i, numVerts, matnr, totface;
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int current_patch = 0;
- int mat_nr = -1;
- bool draw_smooth = false;
- int start_draw_patch = -1, num_draw_patches = 0;
- GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
- return;
- }
- for (i = 0; i < num_base_faces; ++i) {
- const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
- const int num_patches = (num_face_verts == 4) ? face_patches
- : num_face_verts * grid_patches;
- int new_matnr;
- bool new_draw_smooth;
-
- if (faceFlags) {
- new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- new_matnr = (faceFlags[i].mat_nr + 1);
- }
- else {
- new_draw_smooth = true;
- new_matnr = 1;
- }
- if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
- if (num_draw_patches != 0) {
- setMaterial(userData, mat_nr, &gattribs);
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- start_draw_patch = current_patch;
- num_draw_patches = num_patches;
- mat_nr = new_matnr;
- draw_smooth = new_draw_smooth;
- }
- else {
- num_draw_patches += num_patches;
- }
- current_patch += num_patches;
- }
- if (num_draw_patches != 0) {
- setMaterial(userData, mat_nr, &gattribs);
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
- matnr = -1;
-
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
- DM_draw_attrib_vertex_uniforms(&attribs); \
-} (void)0
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (a = 0, i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- const float (*ln)[3] = NULL;
- int S, x, y, drawSmooth;
- int index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int origIndex = ccgDM_getFaceMapIndex(ss, f);
- int new_matnr;
-
- numVerts = ccgSubSurf_getFaceNumVerts(f);
-
- /* get flags */
- if (faceFlags) {
- drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
- new_matnr = faceFlags[index].mat_nr + 1;
- }
- else {
- drawSmooth = 1;
- new_matnr = 1;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
-
- /* material */
- if (new_matnr != matnr) {
- setMaterial(userData, matnr = new_matnr, &gattribs);
- DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- }
-
- /* face hiding */
- if ((setFace && (origIndex != ORIGINDEX_NONE) && !setFace(userData, origIndex))) {
- a += gridFaces * gridFaces * numVerts;
- continue;
- }
-
- /* draw face*/
- glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- CCGElem *vda, *vdb;
-
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(ln[1]);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glNormal3fv(ln[2]);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glNormal3fv(ln[3]);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glNormal3fv(ln[0]);
- glVertex3fv(aco);
-
- ln += 4;
- a++;
- }
- }
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
- vda = CCG_grid_elem(&key, faceGridData, x, y);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 0);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 1);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- if (x != gridFaces - 1)
- a++;
- }
-
- vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
- vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- PASSATTRIB(0, 0, 3);
- glNormal3fv(CCG_elem_no(&key, vda));
- glVertex3fv(CCG_elem_co(&key, vda));
-
- PASSATTRIB(0, 1, 2);
- glNormal3fv(CCG_elem_no(&key, vdb));
- glVertex3fv(CCG_elem_co(&key, vdb));
-
- glEnd();
-
- a++;
- }
- }
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_glNormalFast(aco, bco, cco, dco);
-
- PASSATTRIB(0, 1, 1);
- glVertex3fv(dco);
- PASSATTRIB(1, 1, 2);
- glVertex3fv(cco);
- PASSATTRIB(1, 0, 3);
- glVertex3fv(bco);
- PASSATTRIB(0, 0, 0);
- glVertex3fv(aco);
-
- a++;
- }
- }
- glEnd();
- }
- }
- }
-
- glShadeModel(GL_SMOOTH);
-#undef PASSATTRIB
-}
-
-static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
- DMSetDrawOptionsTex drawParams,
- DMSetDrawOptionsMappedTex drawParamsMapped,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- int colType;
- const MLoopCol *mloopcol = NULL;
- MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- DMDrawOption draw_option;
- int i, totpoly;
- bool flush;
- const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
- const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
- unsigned int next_actualFace;
- unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
- int mat_index;
- int tot_element, start_element, tot_drawn;
-
- if (use_colors) {
- colType = CD_TEXTURE_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- if (!mloopcol) {
- colType = CD_PREVIEW_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- if (!mloopcol) {
- colType = CD_MLOOPCOL;
- mloopcol = dm->getLoopDataArray(dm, colType);
- }
- }
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) {
- return;
- }
- if (drawParams == NULL) {
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
- return;
- }
- const int level = ccgSubSurf_getSubdivisionLevels(ss);
- const int face_side = 1 << level;
- const int grid_side = 1 << (level - 1);
- const int face_patches = face_side * face_side;
- const int grid_patches = grid_side * grid_side;
- const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
- int current_patch = 0;
- int mat_nr = -1;
- int start_draw_patch = 0, num_draw_patches = 0;
- bool draw_smooth = false;
- for (i = 0; i < num_base_faces; ++i) {
- const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
- const int num_patches = (num_face_verts == 4) ? face_patches
- : num_face_verts * grid_patches;
- if (faceFlags) {
- mat_nr = faceFlags[i].mat_nr;
- draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
- }
- else {
- mat_nr = 0;
- draw_smooth = false;
- }
-
- if (drawParams != NULL) {
- MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL;
- draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
- }
- else {
- draw_option = (drawParamsMapped)
- ? drawParamsMapped(userData, i, mat_nr)
- : DM_DRAW_OPTION_NORMAL;
- }
-
- flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1);
-
- const int next_face = min_ii(i + 1, num_base_faces - 1);
- if (!flush && compareDrawOptions) {
- flush |= compareDrawOptions(userData, i, next_face) == 0;
- }
- if (!flush && faceFlags) {
- bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH);
- flush |= (new_draw_smooth != draw_smooth);
- }
-
- current_patch += num_patches;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- num_draw_patches += num_patches;
- }
- if (num_draw_patches != 0) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss,
- true,
- start_draw_patch,
- num_draw_patches);
- }
- start_draw_patch = current_patch;
- num_draw_patches = 0;
- }
- else {
- num_draw_patches += num_patches;
- }
- }
- glShadeModel(GL_SMOOTH);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
- GPU_vertex_setup(dm);
- GPU_normal_setup(dm);
- GPU_triangle_setup(dm);
- if (flag & DM_DRAW_USE_TEXPAINT_UV)
- GPU_texpaint_uv_setup(dm);
- else
- GPU_uv_setup(dm);
- if (mloopcol) {
- GPU_color_setup(dm, colType);
- }
-
- next_actualFace = 0;
-
- /* lastFlag = 0; */ /* UNUSED */
- for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
- GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
- next_actualFace = bufmat->polys[0];
- totpoly = bufmat->totpolys;
-
- tot_element = 0;
- tot_drawn = 0;
- start_element = 0;
-
- for (i = 0; i < totpoly; i++) {
- int polyindex = bufmat->polys[i];
- CCGFace *f = ccgdm->faceMap[polyindex].face;
- int numVerts = ccgSubSurf_getFaceNumVerts(f);
- int index = ccgDM_getFaceMapIndex(ss, f);
- int orig_index = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
- int mat_nr;
- int facequads = numVerts * gridFaces * gridFaces;
- int actualFace = ccgdm->faceMap[polyindex].startFace;
-
- if (i != totpoly - 1) {
- polyindex = bufmat->polys[i + 1];
- next_actualFace = ccgdm->faceMap[polyindex].startFace;
- }
-
- if (faceFlags) {
- mat_nr = faceFlags[orig_index].mat_nr;
- }
- else {
- mat_nr = 0;
- }
-
- if (drawParams) {
- MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[actualFace] : NULL;
- draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
- }
- else if (index != ORIGINDEX_NONE)
- draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL;
- else
- draw_option = DM_DRAW_OPTION_NORMAL;
-
- /* flush buffer if current triangle isn't drawable or it's last triangle */
- flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1);
-
- if (!flush && compareDrawOptions) {
- /* also compare draw options and flush buffer if they're different
- * need for face selection highlight in edit mode */
- flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
- }
-
- tot_element += facequads * 6;
-
- if (flush) {
- if (draw_option != DM_DRAW_OPTION_SKIP)
- tot_drawn += facequads * 6;
-
- if (tot_drawn) {
- if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL)
- GPU_color_switch(1);
- else
- GPU_color_switch(0);
-
- GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
- tot_drawn = 0;
- }
-
- start_element = tot_element;
- }
- else {
- tot_drawn += facequads * 6;
- }
- }
- }
-
-
- GPU_buffers_unbind();
-}
-
-static void ccgDM_drawFacesTex(DerivedMesh *dm,
- DMSetDrawOptionsTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
-}
-
-static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
- DMSetDrawOptionsMappedTex setDrawOptions,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
-}
-
-/* same as cdDM_drawUVEdges */
-static void ccgDM_drawUVEdges(DerivedMesh *dm)
-{
- MPoly *mpoly = dm->getPolyArray(dm);
- int totpoly = dm->getNumPolys(dm);
- int prevstart = 0;
- bool prevdraw = true;
- int curpos = 0;
- int i;
-
- GPU_uvedge_setup(dm);
- for (i = 0; i < totpoly; i++, mpoly++) {
- const bool draw = (mpoly->flag & ME_HIDE) == 0;
-
- if (prevdraw != draw) {
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- prevstart = curpos;
- }
-
- curpos += 2 * mpoly->totloop;
- prevdraw = draw;
- }
- if (prevdraw && (curpos != prevstart)) {
- glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
- }
- GPU_buffers_unbind();
-}
-
-static void ccgDM_drawMappedFaces(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetMaterial setMaterial,
- DMCompareDrawOptions compareDrawOptions,
- void *userData, DMDrawFlag flag)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- MLoopCol *mloopcol = NULL;
- const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
- int i, gridSize = ccgSubSurf_getGridSize(ss);
- DMFlagMat *faceFlags = ccgdm->faceFlags;
- int useColors = flag & DM_DRAW_USE_COLORS;
- int gridFaces = gridSize - 1, totface;
- int prev_mat_nr = -1;
-
- if (ccgdm->pbvh) {
- if (G.debug_value == 14)
- BKE_pbvh_draw_BB(ccgdm->pbvh);
- }
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- int new_matnr;
- bool draw_smooth, do_draw = true;
- if (setDrawOptions == NULL) {
- /* TODO(sergey): This is for cases when vertex colors or weights
- * are visualising. Currently we don't have CD layers for this data
- * and here we only make it so there's no garbage displayed.
- *
- * In the future we'll either need to have CD for this data or pass
- * this data as face-varying or vertex-varying data in OSD mesh.
- */
- glColor3f(0.8f, 0.8f, 0.8f);
- }
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
- return;
- }
- if (faceFlags) {
- draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
- new_matnr = (faceFlags[0].mat_nr + 1);
- }
- else {
- draw_smooth = true;
- new_matnr = 1;
- }
- if (setMaterial) {
- setMaterial(new_matnr, NULL);
- }
- if (setDrawOptions) {
- if (setDrawOptions(userData, 0) == DM_DRAW_OPTION_SKIP) {
- do_draw = false;
- }
- }
- if (do_draw) {
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
- glShadeModel(GL_SMOOTH);
- }
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
-
- /* currently unused -- each original face is handled separately */
- (void)compareDrawOptions;
-
- if (useColors) {
- mloopcol = dm->getLoopDataArray(dm, CD_PREVIEW_MLOOPCOL);
- if (!mloopcol)
- mloopcol = dm->getLoopDataArray(dm, CD_MLOOPCOL);
- }
-
- totface = ccgSubSurf_getNumFaces(ss);
- for (i = 0; i < totface; i++) {
- CCGFace *f = ccgdm->faceMap[i].face;
- int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
- int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
- int origIndex;
- unsigned char *cp = NULL;
- const float (*ln)[3] = NULL;
-
- origIndex = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(f));
-
- if (flag & DM_DRAW_ALWAYS_SMOOTH) drawSmooth = 1;
- else if (faceFlags) drawSmooth = (lnors || (faceFlags[origIndex].flag & ME_SMOOTH));
- else drawSmooth = 1;
-
- if (mloopcol) {
- cp = (unsigned char *)mloopcol;
- mloopcol += gridFaces * gridFaces * numVerts * 4;
- }
-
- if (lnors) {
- ln = lnors;
- lnors += (gridFaces * gridFaces * numVerts) * 4;
- }
-
- {
- DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
-
- if (setMaterial) {
- int mat_nr = faceFlags ? faceFlags[origIndex].mat_nr + 1 : 1;
-
- if (mat_nr != prev_mat_nr) {
- setMaterial(mat_nr, NULL); /* XXX, no faceFlags no material */
- prev_mat_nr = mat_nr;
- }
- }
-
- if (setDrawOptions && (index != ORIGINDEX_NONE))
- draw_option = setDrawOptions(userData, index);
-
- if (draw_option != DM_DRAW_OPTION_SKIP) {
- if (draw_option == DM_DRAW_OPTION_STIPPLE) {
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
- }
-
- for (S = 0; S < numVerts; S++) {
- CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
- if (ln) {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- if (cp) glColor4ubv(&cp[4]);
- glNormal3fv(ln[1]);
- glVertex3fv(d);
- if (cp) glColor4ubv(&cp[8]);
- glNormal3fv(ln[2]);
- glVertex3fv(c);
- if (cp) glColor4ubv(&cp[12]);
- glNormal3fv(ln[3]);
- glVertex3fv(b);
- if (cp) glColor4ubv(&cp[0]);
- glNormal3fv(ln[0]);
- glVertex3fv(a);
-
- if (cp) cp += 16;
- ln += 4;
- }
- }
- glEnd();
- }
- else if (drawSmooth) {
- for (y = 0; y < gridFaces; y++) {
- CCGElem *a, *b;
- glBegin(GL_QUAD_STRIP);
- for (x = 0; x < gridFaces; x++) {
- a = CCG_grid_elem(&key, faceGridData, x, y + 0);
- b = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- if (cp) glColor4ubv(&cp[0]);
- glNormal3fv(CCG_elem_no(&key, a));
- glVertex3fv(CCG_elem_co(&key, a));
- if (cp) glColor4ubv(&cp[4]);
- glNormal3fv(CCG_elem_no(&key, b));
- glVertex3fv(CCG_elem_co(&key, b));
-
- if (x != gridFaces - 1) {
- if (cp) cp += 16;
- }
- }
-
- a = CCG_grid_elem(&key, faceGridData, x, y + 0);
- b = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
- if (cp) glColor4ubv(&cp[12]);
- glNormal3fv(CCG_elem_no(&key, a));
- glVertex3fv(CCG_elem_co(&key, a));
- if (cp) glColor4ubv(&cp[8]);
- glNormal3fv(CCG_elem_no(&key, b));
- glVertex3fv(CCG_elem_co(&key, b));
-
- if (cp) cp += 16;
-
- glEnd();
- }
- }
- else {
- glBegin(GL_QUADS);
- for (y = 0; y < gridFaces; y++) {
- for (x = 0; x < gridFaces; x++) {
- float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
- float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
- float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
- float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
- ccgDM_glNormalFast(a, b, c, d);
-
- if (cp) glColor4ubv(&cp[4]);
- glVertex3fv(d);
- if (cp) glColor4ubv(&cp[8]);
- glVertex3fv(c);
- if (cp) glColor4ubv(&cp[12]);
- glVertex3fv(b);
- if (cp) glColor4ubv(&cp[0]);
- glVertex3fv(a);
-
- if (cp) cp += 16;
- }
- }
- glEnd();
- }
- }
- if (draw_option == DM_DRAW_OPTION_STIPPLE)
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- }
- }
- }
-}
-
-static void ccgDM_drawMappedEdges(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGEdgeIterator ei;
- CCGKey key;
- int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- /* TODO(sergey): Only draw edges from base mesh. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
- if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) {
- ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
- }
- }
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
- int index = ccgDM_getEdgeMapIndex(ss, e);
-
- glBegin(GL_LINE_STRIP);
- if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) {
- if (useAging && !(G.f & G_BACKBUFSEL)) {
- int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
- glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
- }
-
- for (i = 0; i < edgeSize - 1; i++) {
- glVertex3fv(CCG_elem_offset_co(&key, edgeData, i));
- glVertex3fv(CCG_elem_offset_co(&key, edgeData, i + 1));
- }
- }
- glEnd();
- }
-}
-
-static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm,
- DMSetDrawOptions setDrawOptions,
- DMSetDrawInterpOptions setDrawInterpOptions,
- void *userData)
-{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
- CCGSubSurf *ss = ccgdm->ss;
- CCGKey key;
- CCGEdgeIterator ei;
- int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- BLI_assert(!"Not currently supported");
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
- for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
- CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
- CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
- int index = ccgDM_getEdgeMapIndex(ss, e);
-
- glBegin(GL_LINE_STRIP);
- if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) {
- for (i = 0; i < edgeSize; i++) {
- setDrawInterpOptions(userData, index, (float) i / (edgeSize - 1));
-
- if (useAging && !(G.f & G_BACKBUFSEL)) {
- int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
- glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
- }
-
- glVertex3fv(CCG_elem_offset_co(&key, edgeData, i));
- }
- }
- glEnd();
- }
-}
-
static void ccgDM_foreachMappedFaceCenter(
DerivedMesh *dm,
void (*func)(void *userData, int index, const float co[3], const float no[3]),
@@ -4036,7 +1781,7 @@ static void ccgDM_release(DerivedMesh *dm)
if (ccgdm->multires.mmd) {
if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED)
- multires_modifier_update_mdisps(dm);
+ multires_modifier_update_mdisps(dm, NULL);
if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED)
multires_modifier_update_hidden(dm);
}
@@ -4534,7 +2279,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden);
}
else if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
MLoopTri *looptri;
@@ -4558,7 +2303,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
totvert = deformdm->getNumVerts(deformdm);
vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos");
deformdm->getVertCos(deformdm, vertCos);
- BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos);
+ BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos, totvert);
MEM_freeN(vertCos);
}
}
@@ -4671,23 +2416,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
ccgdm->dm.foreachMappedLoop = ccgDM_foreachMappedLoop;
ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
- ccgdm->dm.drawVerts = ccgDM_drawVerts;
- ccgdm->dm.drawEdges = ccgDM_drawEdges;
- ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
- ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
- ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
- ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL;
- ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
- ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
- ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL;
- ccgdm->dm.drawMappedFacesMat = ccgDM_drawMappedFacesMat;
- ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
-
- ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
- ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
- ccgdm->dm.gpuObjectNew = ccgDM_GPUObjectNew;
- ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data;
-
ccgdm->dm.release = ccgDM_release;
}
@@ -4790,14 +2518,6 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
has_edge_cd = ((ccgdm->dm.edgeData.totlayer - (edgeOrigIndex ? 1 : 0)) != 0);
-#if 0
- /* this is not in trunk, can gives problems because colors initialize
- * as black, just don't do it!, it works fine - campbell */
- if (!CustomData_has_layer(&ccgdm->dm.faceData, CD_MCOL))
- DM_add_tessface_layer(&ccgdm->dm, CD_MCOL, CD_CALLOC, NULL);
- mcol = DM_get_tessface_data_layer(&ccgdm->dm, CD_MCOL);
-#endif
-
loopindex = loopindex2 = 0; /* current loop index */
for (index = 0; index < totface; index++) {
CCGFace *f = ccgdm->faceMap[index].face;
@@ -5139,8 +2859,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
*/
return
(flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
- (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE) &&
- (openSubdiv_supportGPUDisplay());
+ (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE);
#else
(void)flags;
return false;
@@ -5150,12 +2869,13 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
+ struct Scene *scene,
float (*vertCos)[3],
SubsurfFlags flags)
{
int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
- int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
+ int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE);
int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
CCGDerivedMesh *result;
bool use_gpu_backend = subsurf_use_gpu_backend(flags);
@@ -5163,7 +2883,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
/* note: editmode calculation can only run once per
* modifier stack evaluation (uses freed cache) [#36299] */
if (flags & SUBSURF_FOR_EDIT_MODE) {
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
+ int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels;
/* TODO(sergey): Same as emCache below. */
if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) {
@@ -5184,7 +2904,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
else if (flags & SUBSURF_USE_RENDER_PARAMS) {
/* Do not use cache in render mode. */
CCGSubSurf *ss;
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels;
+ int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->renderLevels, true) : smd->renderLevels;
if (levels == 0)
return dm;
@@ -5200,7 +2920,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
}
else {
int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
- int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
+ int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels;
CCGSubSurf *ss;
/* It is quite possible there is a much better place to do this. It
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 345168e2000..d512c4ac78e 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -47,8 +47,6 @@
#include "BLI_fileops.h"
#include "DNA_constraint_types.h"
-#include "DNA_controller_types.h"
-#include "DNA_actuator_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -58,7 +56,6 @@
#include "DNA_node_types.h"
#include "DNA_material_types.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index a0399c74be1..c5a208e3aca 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -44,9 +44,7 @@
#include "DNA_key_types.h"
#include "DNA_object_types.h"
-#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
-#include "DNA_world_types.h"
#include "DNA_brush_types.h"
#include "DNA_node_types.h"
#include "DNA_color_types.h"
@@ -213,22 +211,6 @@ void BKE_texture_free(Tex *tex)
}
MEM_SAFE_FREE(tex->coba);
- if (tex->env) {
- BKE_texture_envmap_free(tex->env);
- tex->env = NULL;
- }
- if (tex->pd) {
- BKE_texture_pointdensity_free(tex->pd);
- tex->pd = NULL;
- }
- if (tex->vd) {
- BKE_texture_voxeldata_free(tex->vd);
- tex->vd = NULL;
- }
- if (tex->ot) {
- BKE_texture_ocean_free(tex->ot);
- tex->ot = NULL;
- }
BKE_icon_id_delete((ID *)tex);
BKE_previewimg_free(&tex->preview);
@@ -251,7 +233,6 @@ void BKE_texture_default(Tex *tex)
tex->texfilter = TXF_EWA;
tex->afmax = 8;
tex->xrepeat = tex->yrepeat = 1;
- tex->fie_ima = 2;
tex->sfra = 1;
tex->frames = 0;
tex->offset = 0;
@@ -285,31 +266,6 @@ void BKE_texture_default(Tex *tex)
tex->vn_distm = 0;
tex->vn_coltype = 0;
- if (tex->env) {
- tex->env->stype = ENV_ANIM;
- tex->env->clipsta = 0.1;
- tex->env->clipend = 100;
- tex->env->cuberes = 512;
- tex->env->depth = 0;
- }
-
- if (tex->pd) {
- tex->pd->radius = 0.3f;
- tex->pd->falloff_type = TEX_PD_FALLOFF_STD;
- }
-
- if (tex->vd) {
- tex->vd->resol[0] = tex->vd->resol[1] = tex->vd->resol[2] = 0;
- tex->vd->interp_type = TEX_VD_LINEAR;
- tex->vd->file_format = TEX_VD_SMOKE;
- }
-
- if (tex->ot) {
- tex->ot->output = TEX_OCN_DISPLACEMENT;
- tex->ot->object = NULL;
- }
-
- tex->iuser.fie_ima = 2;
tex->iuser.ok = 1;
tex->iuser.frames = 100;
tex->iuser.sfra = 1;
@@ -319,26 +275,6 @@ void BKE_texture_default(Tex *tex)
void BKE_texture_type_set(Tex *tex, int type)
{
- switch (type) {
-
- case TEX_VOXELDATA:
- if (tex->vd == NULL)
- tex->vd = BKE_texture_voxeldata_add();
- break;
- case TEX_POINTDENSITY:
- if (tex->pd == NULL)
- tex->pd = BKE_texture_pointdensity_add();
- break;
- case TEX_ENVMAP:
- if (tex->env == NULL)
- tex->env = BKE_texture_envmap_add();
- break;
- case TEX_OCEAN:
- if (tex->ot == NULL)
- tex->ot = BKE_texture_ocean_add();
- break;
- }
-
tex->type = type;
}
@@ -476,10 +412,6 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
MEM_freeN(mtex_ar[slot]);
mtex_ar[slot] = NULL;
}
- else if (GS(id->name) == ID_MA) {
- /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
- ((Material *)id)->septex &= ~(1 << slot);
- }
mtex_ar[slot] = BKE_texture_mtex_add();
@@ -498,9 +430,6 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot)
*/
void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const int flag)
{
- /* We never handle usercount here for own data. */
- const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
-
if (!BKE_texture_is_image_user(tex_src)) {
tex_dst->ima = NULL;
}
@@ -508,19 +437,6 @@ void BKE_texture_copy_data(Main *bmain, Tex *tex_dst, const Tex *tex_src, const
if (tex_dst->coba) {
tex_dst->coba = MEM_dupallocN(tex_dst->coba);
}
- if (tex_dst->env) {
- tex_dst->env = BKE_texture_envmap_copy(tex_dst->env, flag_subdata);
- }
- if (tex_dst->pd) {
- tex_dst->pd = BKE_texture_pointdensity_copy(tex_dst->pd, flag_subdata);
- }
- if (tex_dst->vd) {
- tex_dst->vd = MEM_dupallocN(tex_dst->vd);
- }
- if (tex_dst->ot) {
- tex_dst->ot = BKE_texture_ocean_copy(tex_dst->ot, flag_subdata);
- }
-
if (tex_src->nodetree) {
if (tex_src->nodetree->execdata) {
ntreeTexEndExecTree(tex_src->nodetree->execdata);
@@ -562,19 +478,6 @@ Tex *BKE_texture_localize(Tex *tex)
/* image texture: BKE_texture_free also doesn't decrease */
if (texn->coba) texn->coba = MEM_dupallocN(texn->coba);
- if (texn->env) {
- texn->env = BKE_texture_envmap_copy(texn->env, LIB_ID_CREATE_NO_USER_REFCOUNT);
- id_us_min(&texn->env->ima->id);
- }
- if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd, LIB_ID_CREATE_NO_USER_REFCOUNT);
- if (texn->vd) {
- texn->vd = MEM_dupallocN(texn->vd);
- if (texn->vd->dataset)
- texn->vd->dataset = MEM_dupallocN(texn->vd->dataset);
- }
- if (texn->ot) {
- texn->ot = BKE_texture_ocean_copy(tex->ot, LIB_ID_CREATE_NO_USER_REFCOUNT);
- }
texn->preview = NULL;
@@ -593,64 +496,6 @@ void BKE_texture_make_local(Main *bmain, Tex *tex, const bool lib_local)
BKE_id_make_local_generic(bmain, &tex->id, true, lib_local);
}
-Tex *give_current_object_texture(Object *ob)
-{
- Material *ma, *node_ma;
- Tex *tex = NULL;
-
- if (ob == NULL) return NULL;
- if (ob->totcol == 0 && !(ob->type == OB_LAMP)) return NULL;
-
- if (ob->type == OB_LAMP) {
- tex = give_current_lamp_texture(ob->data);
- }
- else {
- ma = give_current_material(ob, ob->actcol);
-
- if ((node_ma = give_node_material(ma)))
- ma = node_ma;
-
- tex = give_current_material_texture(ma);
- }
-
- return tex;
-}
-
-Tex *give_current_lamp_texture(Lamp *la)
-{
- MTex *mtex = NULL;
- Tex *tex = NULL;
-
- if (la) {
- mtex = la->mtex[(int)(la->texact)];
- if (mtex) tex = mtex->tex;
- }
-
- return tex;
-}
-
-void set_current_lamp_texture(Lamp *la, Tex *newtex)
-{
- int act = la->texact;
-
- if (la->mtex[act] && la->mtex[act]->tex)
- id_us_min(&la->mtex[act]->tex->id);
-
- if (newtex) {
- if (!la->mtex[act]) {
- la->mtex[act] = BKE_texture_mtex_add();
- la->mtex[act]->texco = TEXCO_GLOB;
- }
-
- la->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (la->mtex[act]) {
- MEM_freeN(la->mtex[act]);
- la->mtex[act] = NULL;
- }
-}
-
Tex *give_current_linestyle_texture(FreestyleLineStyle *linestyle)
{
MTex *mtex = NULL;
@@ -686,55 +531,9 @@ void set_current_linestyle_texture(FreestyleLineStyle *linestyle, Tex *newtex)
}
}
-bNode *give_current_material_texture_node(Material *ma)
-{
- if (ma && ma->use_nodes && ma->nodetree)
- return nodeGetActiveID(ma->nodetree, ID_TE);
-
- return NULL;
-}
-
-Tex *give_current_material_texture(Material *ma)
-{
- MTex *mtex = NULL;
- Tex *tex = NULL;
- bNode *node;
-
- if (ma && ma->use_nodes && ma->nodetree) {
- /* first check texture, then material, this works together
- * with a hack that clears the active ID flag for textures on
- * making a material node active */
- node = nodeGetActiveID(ma->nodetree, ID_TE);
-
- if (node) {
- tex = (Tex *)node->id;
- ma = NULL;
- }
- }
-
- if (ma) {
- mtex = ma->mtex[(int)(ma->texact)];
- if (mtex) tex = mtex->tex;
- }
-
- return tex;
-}
-
bool give_active_mtex(ID *id, MTex ***mtex_ar, short *act)
{
switch (GS(id->name)) {
- case ID_MA:
- *mtex_ar = ((Material *)id)->mtex;
- if (act) *act = (((Material *)id)->texact);
- break;
- case ID_WO:
- *mtex_ar = ((World *)id)->mtex;
- if (act) *act = (((World *)id)->texact);
- break;
- case ID_LA:
- *mtex_ar = ((Lamp *)id)->mtex;
- if (act) *act = (((Lamp *)id)->texact);
- break;
case ID_LS:
*mtex_ar = ((FreestyleLineStyle *)id)->mtex;
if (act) *act = (((FreestyleLineStyle *)id)->texact);
@@ -758,15 +557,6 @@ void set_active_mtex(ID *id, short act)
else if (act >= MAX_MTEX) act = MAX_MTEX - 1;
switch (GS(id->name)) {
- case ID_MA:
- ((Material *)id)->texact = act;
- break;
- case ID_WO:
- ((World *)id)->texact = act;
- break;
- case ID_LA:
- ((Lamp *)id)->texact = act;
- break;
case ID_LS:
((FreestyleLineStyle *)id)->texact = act;
break;
@@ -778,100 +568,6 @@ void set_active_mtex(ID *id, short act)
}
}
-void set_current_material_texture(Material *ma, Tex *newtex)
-{
- Tex *tex = NULL;
- bNode *node;
-
- if ((ma->use_nodes && ma->nodetree) &&
- (node = nodeGetActiveID(ma->nodetree, ID_TE)))
- {
- tex = (Tex *)node->id;
- id_us_min(&tex->id);
- if (newtex) {
- node->id = &newtex->id;
- id_us_plus(&newtex->id);
- }
- else {
- node->id = NULL;
- }
- }
- else {
- int act = (int)ma->texact;
-
- tex = (ma->mtex[act]) ? ma->mtex[act]->tex : NULL;
- id_us_min(&tex->id);
-
- if (newtex) {
- if (!ma->mtex[act]) {
- ma->mtex[act] = BKE_texture_mtex_add();
- /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
- ma->septex &= ~(1 << act);
- /* For volumes the default UV texture coordinates are not available. */
- if (ma->material_type == MA_TYPE_VOLUME) {
- ma->mtex[act]->texco = TEXCO_ORCO;
- }
- }
-
- ma->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (ma->mtex[act]) {
- MEM_freeN(ma->mtex[act]);
- ma->mtex[act] = NULL;
- }
- }
-}
-
-bool has_current_material_texture(Material *ma)
-{
- bNode *node;
-
- if (ma && ma->use_nodes && ma->nodetree) {
- node = nodeGetActiveID(ma->nodetree, ID_TE);
-
- if (node)
- return true;
- }
-
- return (ma != NULL);
-}
-
-Tex *give_current_world_texture(World *world)
-{
- MTex *mtex = NULL;
- Tex *tex = NULL;
-
- if (!world) return NULL;
-
- mtex = world->mtex[(int)(world->texact)];
- if (mtex) tex = mtex->tex;
-
- return tex;
-}
-
-void set_current_world_texture(World *wo, Tex *newtex)
-{
- int act = wo->texact;
-
- if (wo->mtex[act] && wo->mtex[act]->tex)
- id_us_min(&wo->mtex[act]->tex->id);
-
- if (newtex) {
- if (!wo->mtex[act]) {
- wo->mtex[act] = BKE_texture_mtex_add();
- wo->mtex[act]->texco = TEXCO_VIEW;
- }
-
- wo->mtex[act]->tex = newtex;
- id_us_plus(&newtex->id);
- }
- else if (wo->mtex[act]) {
- MEM_freeN(wo->mtex[act]);
- wo->mtex[act] = NULL;
- }
-}
-
Tex *give_current_brush_texture(Brush *br)
{
return br->mtex.tex;
@@ -926,65 +622,6 @@ void set_current_particle_texture(ParticleSettings *part, Tex *newtex)
/* ------------------------------------------------------------------------- */
-EnvMap *BKE_texture_envmap_add(void)
-{
- EnvMap *env;
-
- env = MEM_callocN(sizeof(EnvMap), "envmap");
- env->type = ENV_CUBE;
- env->stype = ENV_ANIM;
- env->clipsta = 0.1;
- env->clipend = 100.0;
- env->cuberes = 512;
- env->viewscale = 0.5;
-
- return env;
-}
-
-/* ------------------------------------------------------------------------- */
-
-EnvMap *BKE_texture_envmap_copy(const EnvMap *env, const int flag)
-{
- EnvMap *envn;
- int a;
-
- envn = MEM_dupallocN(env);
- envn->ok = 0;
- for (a = 0; a < 6; a++) {
- envn->cube[a] = NULL;
- }
- if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- id_us_plus((ID *)envn->ima);
- }
-
- return envn;
-}
-
-/* ------------------------------------------------------------------------- */
-
-void BKE_texture_envmap_free_data(EnvMap *env)
-{
- unsigned int part;
-
- for (part = 0; part < 6; part++) {
- if (env->cube[part])
- IMB_freeImBuf(env->cube[part]);
- env->cube[part] = NULL;
- }
- env->ok = 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-void BKE_texture_envmap_free(EnvMap *env)
-{
-
- BKE_texture_envmap_free_data(env);
- MEM_freeN(env);
-
-}
-
-/* ------------------------------------------------------------------------- */
void BKE_texture_pointdensity_init_data(PointDensity *pd)
{
@@ -1057,77 +694,8 @@ void BKE_texture_pointdensity_free(PointDensity *pd)
BKE_texture_pointdensity_free_data(pd);
MEM_freeN(pd);
}
-
-/* ------------------------------------------------------------------------- */
-
-void BKE_texture_voxeldata_free_data(VoxelData *vd)
-{
- if (vd->dataset) {
- MEM_freeN(vd->dataset);
- vd->dataset = NULL;
- }
-
-}
-
-void BKE_texture_voxeldata_free(VoxelData *vd)
-{
- BKE_texture_voxeldata_free_data(vd);
- MEM_freeN(vd);
-}
-
-VoxelData *BKE_texture_voxeldata_add(void)
-{
- VoxelData *vd;
-
- vd = MEM_callocN(sizeof(VoxelData), "voxeldata");
- vd->dataset = NULL;
- vd->resol[0] = vd->resol[1] = vd->resol[2] = 1;
- vd->interp_type = TEX_VD_LINEAR;
- vd->file_format = TEX_VD_SMOKE;
- vd->int_multiplier = 1.0;
- vd->extend = TEX_CLIP;
- vd->object = NULL;
- vd->cachedframe = -1;
- vd->ok = 0;
-
- return vd;
-}
-
-VoxelData *BKE_texture_voxeldata_copy(VoxelData *vd)
-{
- VoxelData *vdn;
-
- vdn = MEM_dupallocN(vd);
- vdn->dataset = NULL;
-
- return vdn;
-}
-
/* ------------------------------------------------------------------------- */
-OceanTex *BKE_texture_ocean_add(void)
-{
- OceanTex *ot;
-
- ot = MEM_callocN(sizeof(struct OceanTex), "ocean texture");
- ot->output = TEX_OCN_DISPLACEMENT;
- ot->object = NULL;
-
- return ot;
-}
-
-OceanTex *BKE_texture_ocean_copy(const OceanTex *ot, const int UNUSED(flag))
-{
- OceanTex *otn = MEM_dupallocN(ot);
-
- return otn;
-}
-
-void BKE_texture_ocean_free(struct OceanTex *ot)
-{
- MEM_freeN(ot);
-}
-
/**
* \returns true if this texture can use its #Texture.ima (even if its NULL)
*/
@@ -1138,15 +706,6 @@ bool BKE_texture_is_image_user(const struct Tex *tex)
{
return true;
}
- case TEX_ENVMAP:
- {
- if (tex->env) {
- if (tex->env->stype == ENV_LOAD) {
- return true;
- }
- }
- break;
- }
}
return false;
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index a3536cd0d68..f19f27c85a7 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -61,6 +61,7 @@
#include "BKE_movieclip.h"
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BKE_layer.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -398,17 +399,17 @@ MovieTrackingReconstruction *BKE_tracking_get_active_reconstruction(MovieTrackin
/* Get transformation matrix for a given object which is used
* for parenting motion tracker reconstruction to 3D world.
*/
-void BKE_tracking_get_camera_object_matrix(Scene *scene, Object *ob, float mat[4][4])
+void BKE_tracking_get_camera_object_matrix(struct Depsgraph *depsgraph, Scene *scene, Object *ob, float mat[4][4])
{
if (!ob) {
if (scene->camera)
ob = scene->camera;
else
- ob = BKE_scene_camera_find(scene);
+ ob = BKE_view_layer_camera_find(BKE_view_layer_context_active_PLACEHOLDER(scene));
}
if (ob)
- BKE_object_where_is_calc_mat4(scene, ob, mat);
+ BKE_object_where_is_calc_mat4(depsgraph, scene, ob, mat);
else
unit_m4(mat);
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index 331db5b6ff0..aae9985bc24 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -982,7 +982,7 @@ static void initialize_track_for_stabilization(StabContext *ctx,
static void initialize_all_tracks(StabContext *ctx, float aspect)
{
- size_t i, track_cnt = 0;
+ size_t i, track_len = 0;
MovieClip *clip = ctx->clip;
MovieTracking *tracking = ctx->tracking;
MovieTrackingTrack *track;
@@ -1011,20 +1011,20 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
track);
local_data->is_init_for_stabilization = false;
- ++track_cnt;
+ ++track_len;
}
- if (!track_cnt) {
+ if (!track_len) {
return;
}
- order = MEM_mallocN(track_cnt * sizeof(TrackInitOrder),
+ order = MEM_mallocN(track_len * sizeof(TrackInitOrder),
"stabilization track order");
if (!order) {
return;
}
- track_cnt = establish_track_initialization_order(ctx, order);
- if (track_cnt == 0) {
+ track_len = establish_track_initialization_order(ctx, order);
+ if (track_len == 0) {
goto cleanup;
}
@@ -1032,7 +1032,7 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
average_marker_positions(ctx, reference_frame, average_pos);
setup_pivot(average_pos, pivot);
- for (i = 0; i < track_cnt; ++i) {
+ for (i = 0; i < track_len; ++i) {
track = order[i].data;
if (reference_frame != order[i].reference_frame) {
reference_frame = order[i].reference_frame;
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index 0ebfb4065e4..abc53bf031a 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -39,6 +39,8 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_main.h"
#include "BKE_undo_system.h"
@@ -413,12 +415,21 @@ UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char
return BKE_undosys_step_push_init_with_type(ustack, C, name, ut);
}
+/**
+ * \param C: Can be NULL from some callers if their encoding function doesn't need it
+ */
bool BKE_undosys_step_push_with_type(UndoStack *ustack, bContext *C, const char *name, const UndoType *ut)
{
UNDO_NESTED_ASSERT(false);
undosys_stack_validate(ustack, false);
bool is_not_empty = ustack->step_active != NULL;
+ /* Might not be final place for this to be called - probably only want to call it from some
+ * undo handlers, not all of them? */
+ if (BKE_override_static_is_enabled()) {
+ BKE_main_override_static_operations_create(G.main, false);
+ }
+
/* Remove all undos after (also when 'ustack->step_active == NULL'). */
while (ustack->steps.last != ustack->step_active) {
UndoStep *us_iter = ustack->steps.last;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 3a903eb31c1..e2a0837b938 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -35,6 +35,8 @@
#include "BLI_string.h"
#include "BLI_string_utf8.h"
+#include "DNA_scene_types.h"
+
#include "BKE_unit.h" /* own include */
#ifdef WIN32
@@ -108,6 +110,8 @@ typedef struct bUnitCollection {
int length; /* to quickly find the last item */
} bUnitCollection;
+#define UNIT_COLLECTION_LENGTH(def) (sizeof(def) / sizeof(bUnitDef) - 1)
+
/* Dummy */
static struct bUnitDef buDummyDef[] = { {"", NULL, "", NULL, NULL, 1.0, 0.0}, {NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}};
static struct bUnitCollection buDummyCollection = {buDummyDef, 0, 0, sizeof(buDummyDef)};
@@ -121,7 +125,7 @@ static const struct bUnitDef buMetricLenDef[] = {
{"decimeter", "decimeters", "dm", NULL, "10 Centimeters", UN_SC_DM, 0.0, B_UNIT_DEF_SUPPRESS},
{"centimeter", "centimeters", "cm", NULL, "Centimeters", UN_SC_CM, 0.0, B_UNIT_DEF_NONE},
{"millimeter", "millimeters", "mm", NULL, "Millimeters", UN_SC_MM, 0.0, B_UNIT_DEF_NONE | B_UNIT_DEF_TENTH},
- {"micrometer", "micrometers", "µm", "um", "Micrometers", UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
+ {"micrometer", "micrometers", "µm", "um", "Micrometers", UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
/* These get displayed because of float precision problems in the transform header,
* could work around, but for now probably people wont use these */
@@ -131,7 +135,7 @@ static const struct bUnitDef buMetricLenDef[] = {
#endif
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static const struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, sizeof(buMetricLenDef) / sizeof(bUnitDef)};
+static const struct bUnitCollection buMetricLenCollection = {buMetricLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricLenDef)};
static struct bUnitDef buImperialLenDef[] = {
{"mile", "miles", "mi", "m", "Miles", UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
@@ -143,7 +147,7 @@ static struct bUnitDef buImperialLenDef[] = {
{"thou", "thou", "thou", "mil", "Thou", UN_SC_MIL, 0.0, B_UNIT_DEF_NONE}, /* plural for thou has no 's' */
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buImperialLenCollection = {buImperialLenDef, 4, 0, sizeof(buImperialLenDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialLenCollection = {buImperialLenDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialLenDef)};
/* Areas */
static struct bUnitDef buMetricAreaDef[] = {
@@ -157,7 +161,7 @@ static struct bUnitDef buMetricAreaDef[] = {
{"square micrometer", "square micrometers", "µm²", "um2", "Square Micrometers", UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buMetricAreaCollection = {buMetricAreaDef, 3, 0, sizeof(buMetricAreaDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricAreaCollection = {buMetricAreaDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricAreaDef)};
static struct bUnitDef buImperialAreaDef[] = {
{"square mile", "square miles", "sq mi", "sq m", "Square Miles", UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
@@ -169,7 +173,7 @@ static struct bUnitDef buImperialAreaDef[] = {
{"square thou", "square thous", "sq mil", NULL, "Square Thous", UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buImperialAreaCollection = {buImperialAreaDef, 4, 0, sizeof(buImperialAreaDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialAreaCollection = {buImperialAreaDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialAreaDef)};
/* Volumes */
static struct bUnitDef buMetricVolDef[] = {
@@ -183,7 +187,7 @@ static struct bUnitDef buMetricVolDef[] = {
{"cubic micrometer", "cubic micrometers", "µm³", "um3", "Cubic Micrometers", UN_SC_UM * UN_SC_UM * UN_SC_UM, 0.0, B_UNIT_DEF_NONE},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buMetricVolCollection = {buMetricVolDef, 3, 0, sizeof(buMetricVolDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricVolCollection = {buMetricVolDef, 3, 0, UNIT_COLLECTION_LENGTH(buMetricVolDef)};
static struct bUnitDef buImperialVolDef[] = {
{"cubic mile", "cubic miles", "cu mi", "cu m", "Cubic Miles", UN_SC_MI * UN_SC_MI * UN_SC_MI, 0.0, B_UNIT_DEF_NONE},
@@ -195,11 +199,11 @@ static struct bUnitDef buImperialVolDef[] = {
{"cubic thou", "cubic thous", "cu mil", NULL, "Cubic Thous", UN_SC_MIL * UN_SC_MIL * UN_SC_MIL, 0.0, B_UNIT_DEF_NONE},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buImperialVolCollection = {buImperialVolDef, 4, 0, sizeof(buImperialVolDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialVolCollection = {buImperialVolDef, 4, 0, UNIT_COLLECTION_LENGTH(buImperialVolDef)};
/* Mass */
static struct bUnitDef buMetricMassDef[] = {
- {"ton", "tonnes", "ton", "t", "1000 Kilograms", UN_SC_MTON, 0.0, B_UNIT_DEF_NONE},
+ {"ton", "tonnes", "ton", "t", "Tonnes", UN_SC_MTON, 0.0, B_UNIT_DEF_NONE},
{"quintal", "quintals", "ql", "q", "100 Kilograms", UN_SC_QL, 0.0, B_UNIT_DEF_SUPPRESS},
{"kilogram", "kilograms", "kg", NULL, "Kilograms", UN_SC_KG, 0.0, B_UNIT_DEF_NONE}, /* base unit */
{"hectogram", "hectograms", "hg", NULL, "Hectograms", UN_SC_HG, 0.0, B_UNIT_DEF_SUPPRESS},
@@ -208,7 +212,7 @@ static struct bUnitDef buMetricMassDef[] = {
{"milligram", "milligrams", "mg", NULL, "Milligrams", UN_SC_MG, 0.0, B_UNIT_DEF_NONE},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buMetricMassCollection = {buMetricMassDef, 2, 0, sizeof(buMetricMassDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricMassCollection = {buMetricMassDef, 2, 0, UNIT_COLLECTION_LENGTH(buMetricMassDef)};
static struct bUnitDef buImperialMassDef[] = {
{"ton", "tonnes", "ton", "t", "Tonnes", UN_SC_ITON, 0.0, B_UNIT_DEF_NONE},
@@ -218,7 +222,7 @@ static struct bUnitDef buImperialMassDef[] = {
{"ounce", "ounces", "oz", NULL, "Ounces", UN_SC_OZ, 0.0, B_UNIT_DEF_NONE},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buImperialMassCollection = {buImperialMassDef, 3, 0, sizeof(buImperialMassDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialMassCollection = {buImperialMassDef, 3, 0, UNIT_COLLECTION_LENGTH(buImperialMassDef)};
/* Even if user scales the system to a point where km^3 is used, velocity and
* acceleration aren't scaled: that's why we have so few units for them */
@@ -229,27 +233,27 @@ static struct bUnitDef buMetricVelDef[] = {
{"kilometer per hour", "kilometers per hour", "km/h", NULL, "Kilometers per hour", UN_SC_KM / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buMetricVelCollection = {buMetricVelDef, 0, 0, sizeof(buMetricVelDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricVelCollection = {buMetricVelDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricVelDef)};
static struct bUnitDef buImperialVelDef[] = {
{"foot per second", "feet per second", "ft/s", "fps", "Feet per second", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
{"mile per hour", "miles per hour", "mph", NULL, "Miles per hour", UN_SC_MI / 3600.0f, 0.0, B_UNIT_DEF_SUPPRESS},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buImperialVelCollection = {buImperialVelDef, 0, 0, sizeof(buImperialVelDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialVelCollection = {buImperialVelDef, 0, 0, UNIT_COLLECTION_LENGTH(buImperialVelDef)};
/* Acceleration */
static struct bUnitDef buMetricAclDef[] = {
{"meter per second squared", "meters per second squared", "m/s²", "m/s2", "Meters per second squared", UN_SC_M, 0.0, B_UNIT_DEF_NONE}, /* base unit */
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buMetricAclCollection = {buMetricAclDef, 0, 0, sizeof(buMetricAclDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buMetricAclCollection = {buMetricAclDef, 0, 0, UNIT_COLLECTION_LENGTH(buMetricAclDef)};
static struct bUnitDef buImperialAclDef[] = {
{"foot per second squared", "feet per second squared", "ft/s²", "ft/s2", "Feet per second squared", UN_SC_FT, 0.0, B_UNIT_DEF_NONE}, /* base unit */
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buImperialAclCollection = {buImperialAclDef, 0, 0, sizeof(buImperialAclDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buImperialAclCollection = {buImperialAclDef, 0, 0, UNIT_COLLECTION_LENGTH(buImperialAclDef)};
/* Time */
static struct bUnitDef buNaturalTimeDef[] = {
@@ -262,7 +266,7 @@ static struct bUnitDef buNaturalTimeDef[] = {
{"microsecond", "microseconds", "µs", "us", "Microseconds", 0.000001, 0.0, B_UNIT_DEF_NONE},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buNaturalTimeCollection = {buNaturalTimeDef, 3, 0, sizeof(buNaturalTimeDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buNaturalTimeCollection = {buNaturalTimeDef, 3, 0, UNIT_COLLECTION_LENGTH(buNaturalTimeDef)};
static struct bUnitDef buNaturalRotDef[] = {
@@ -274,7 +278,7 @@ static struct bUnitDef buNaturalRotDef[] = {
// {"turn", "turns", "t", NULL, "Turns", 1.0 / (M_PI * 2.0), 0.0, B_UNIT_DEF_NONE},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buNaturalRotCollection = {buNaturalRotDef, 0, 0, sizeof(buNaturalRotDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buNaturalRotCollection = {buNaturalRotDef, 0, 0, UNIT_COLLECTION_LENGTH(buNaturalRotDef)};
/* Camera Lengths */
static struct bUnitDef buCameraLenDef[] = {
@@ -285,7 +289,7 @@ static struct bUnitDef buCameraLenDef[] = {
{"micrometer", "micrometers", "µm", "um", "Micrometers", UN_SC_MM, 0.0, B_UNIT_DEF_SUPPRESS},
{NULL, NULL, NULL, NULL, NULL, 0.0, 0.0}
};
-static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, sizeof(buCameraLenDef) / sizeof(bUnitDef)};
+static struct bUnitCollection buCameraLenCollection = {buCameraLenDef, 3, 0, UNIT_COLLECTION_LENGTH(buCameraLenDef)};
#define UNIT_SYSTEM_TOT (((sizeof(bUnitSystems) / B_UNIT_TYPE_TOT) / sizeof(void *)) - 1)
@@ -341,9 +345,12 @@ static const bUnitDef *unit_best_fit(
static void unit_dual_convert(
double value, const bUnitCollection *usys,
bUnitDef const **r_unit_a, bUnitDef const **r_unit_b,
- double *r_value_a, double *r_value_b)
+ double *r_value_a, double *r_value_b,
+ const bUnitDef *main_unit)
{
- const bUnitDef *unit = unit_best_fit(value, usys, NULL, 1);
+ const bUnitDef *unit;
+ if (main_unit) unit = main_unit;
+ else unit = unit_best_fit(value, usys, NULL, 1);
*r_value_a = (value < 0.0 ? ceil : floor)(value / unit->scalar) * unit->scalar;
*r_value_b = value - (*r_value_a);
@@ -405,17 +412,6 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, con
while (unit->name_short[j] && (i < len_max)) {
str[i++] = unit->name_short[j++];
}
-#if 0
- if (pad) {
- /* this loop only runs if so many zeros were removed that
- * the unit name only used padded chars,
- * In that case add padding for the name. */
-
- while (i <= len + j && (i < len_max)) {
- str[i++] = pad;
- }
- }
-#endif
}
/* terminate no matter what's done with padding above */
@@ -426,43 +422,135 @@ static size_t unit_as_string(char *str, int len_max, double value, int prec, con
return i;
}
-/* Used for drawing number buttons, try keep fast.
- * Return the length of the generated string.
- */
-size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
+static bool unit_should_be_split(int type)
{
- const bUnitCollection *usys = unit_get_system(system, type);
+ return ELEM(type, B_UNIT_LENGTH, B_UNIT_MASS, B_UNIT_TIME, B_UNIT_CAMERA);
+}
- if (usys == NULL || usys->units[0].name == NULL)
- usys = &buDummyCollection;
+typedef struct {
+ int system;
+ int rotation;
+ /* USER_UNIT_ADAPTIVE means none, otherwise the value is the index in the collection */
+ int length;
+ int mass;
+ int time;
+} PreferredUnits;
- /* split output makes sense only for length, mass and time */
- if (split && (type == B_UNIT_LENGTH || type == B_UNIT_MASS || type == B_UNIT_TIME || type == B_UNIT_CAMERA)) {
- const bUnitDef *unit_a, *unit_b;
- double value_a, value_b;
+static PreferredUnits preferred_units_from_UnitSettings(const UnitSettings *settings)
+{
+ PreferredUnits units = { 0 };
+ units.system = settings->system;
+ units.rotation = settings->system_rotation;
+ units.length = settings->length_unit;
+ units.mass = settings->mass_unit;
+ units.time = settings->time_unit;
+ return units;
+}
- unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b);
+static size_t unit_as_string_splitted(
+ char *str, int len_max, double value, int prec,
+ const bUnitCollection *usys, const bUnitDef *main_unit)
+{
+ const bUnitDef *unit_a, *unit_b;
+ double value_a, value_b;
- /* check the 2 is a smaller unit */
- if (unit_b > unit_a) {
- size_t i;
- i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0');
+ unit_dual_convert(value, usys, &unit_a, &unit_b, &value_a, &value_b, main_unit);
- prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar);
- prec = max_ii(prec, 0);
+ /* check the 2 is a smaller unit */
+ if (unit_b > unit_a) {
+ size_t i;
+ i = unit_as_string(str, len_max, value_a, prec, usys, unit_a, '\0');
- /* is there enough space for at least 1 char of the next unit? */
- if (i + 2 < len_max) {
- str[i++] = ' ';
+ prec -= integer_digits_d(value_a / unit_b->scalar) - integer_digits_d(value_b / unit_b->scalar);
+ prec = max_ii(prec, 0);
- /* use low precision since this is a smaller unit */
- i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0');
- }
- return i;
+ /* is there enough space for at least 1 char of the next unit? */
+ if (i + 2 < len_max) {
+ str[i++] = ' ';
+
+ /* use low precision since this is a smaller unit */
+ i += unit_as_string(str + i, len_max - i, value_b, prec, usys, unit_b, '\0');
}
+ return i;
+ }
+
+ return -1;
+}
+
+static bool is_valid_unit_collection(const bUnitCollection *usys)
+{
+ return usys != NULL && usys->units[0].name != NULL;
+}
+
+static const bUnitDef *get_preferred_unit_if_used(int type, PreferredUnits units)
+{
+ const bUnitCollection *usys = unit_get_system(units.system, type);
+ if (!is_valid_unit_collection(usys)) return NULL;
+
+ int max_offset = usys->length - 1;
+
+ switch (type) {
+ case B_UNIT_LENGTH:
+ case B_UNIT_AREA:
+ case B_UNIT_VOLUME:
+ if (units.length == USER_UNIT_ADAPTIVE) return NULL;
+ return usys->units + MIN2(units.length, max_offset);
+ case B_UNIT_MASS:
+ if (units.mass == USER_UNIT_ADAPTIVE) return NULL;
+ return usys->units + MIN2(units.mass, max_offset);
+ case B_UNIT_TIME:
+ if (units.time == USER_UNIT_ADAPTIVE) return NULL;
+ return usys->units + MIN2(units.time, max_offset);
+ case B_UNIT_ROTATION:
+ if (units.rotation == 0) return usys->units + 0;
+ else if (units.rotation == USER_UNIT_ROT_RADIANS) return usys->units + 3;
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/* Return the length of the generated string. */
+static size_t unit_as_string_main(
+ char *str, int len_max, double value, int prec,
+ int type, bool split, bool pad, PreferredUnits units)
+{
+ const bUnitCollection *usys = unit_get_system(units.system, type);
+ const bUnitDef *main_unit = NULL;
+
+ if (!is_valid_unit_collection(usys)) {
+ usys = &buDummyCollection;
+ }
+ else {
+ main_unit = get_preferred_unit_if_used(type, units);
}
- return unit_as_string(str, len_max, value, prec, usys, NULL, pad ? ' ' : '\0');
+ if (split && unit_should_be_split(type)) {
+ int length = unit_as_string_splitted(str, len_max, value, prec, usys, main_unit);
+ /* failed when length is negative, fallback to no split */
+ if (length >= 0) return length;
+ }
+
+ return unit_as_string(str, len_max, value, prec, usys, main_unit, pad ? ' ' : '\0');
+}
+
+size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad)
+{
+ PreferredUnits units;
+ units.system = system;
+ units.rotation = 0;
+ units.length = USER_UNIT_ADAPTIVE;
+ units.mass = USER_UNIT_ADAPTIVE;
+ units.time = USER_UNIT_ADAPTIVE;
+ return unit_as_string_main(str, len_max, value, prec, type, split, pad, units);
+}
+
+size_t bUnit_AsString2(char *str, int len_max, double value, int prec, int type, const UnitSettings *settings, bool pad)
+{
+ bool do_split = (settings->flag & USER_UNIT_OPT_SPLIT) != 0;
+ PreferredUnits units = preferred_units_from_UnitSettings(settings);
+ return unit_as_string_main(str, len_max, value, prec, type, do_split, pad, units);
}
BLI_INLINE bool isalpha_or_utf8(const int ch)
@@ -631,6 +719,27 @@ static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const c
return unit;
}
+bool bUnit_ContainsUnit(const char *str, int system, int type)
+{
+ const bUnitCollection *usys = unit_get_system(system, type);
+ if (!is_valid_unit_collection(usys)) return false;
+
+ for (int i = 0; i < usys->length; i++) {
+ if (unit_find(str, usys->units + i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+double bUnit_PreferredUnitScalar(const struct UnitSettings *settings, int type)
+{
+ PreferredUnits units = preferred_units_from_UnitSettings(settings);
+ const bUnitDef *unit = get_preferred_unit_if_used(type, units);
+ if (unit == NULL) return 1.0;
+ else return unit->scalar;
+}
+
/* make a copy of the string that replaces the units with numbers
* this is used before parsing
* This is only used when evaluating user input and can afford to be a bit slower
@@ -649,16 +758,13 @@ static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const c
bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
const bUnitCollection *usys = unit_get_system(system, type);
+ if (!is_valid_unit_collection(usys)) return false;
const bUnitDef *unit = NULL, *default_unit;
double scale_pref_base = scale_pref;
char str_tmp[TEMP_STR_SIZE];
bool changed = false;
- if (usys == NULL || usys->units[0].name == NULL) {
- return changed;
- }
-
/* make lowercase */
BLI_str_tolower_ascii(str, len_max);
@@ -824,6 +930,11 @@ int bUnit_GetBaseUnit(const void *usys_pt)
return ((bUnitCollection *)usys_pt)->base_unit;
}
+int bUnit_GetBaseUnitOfType(int system, int type)
+{
+ return unit_get_system(system, type)->base_unit;
+}
+
const char *bUnit_GetName(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].name;
@@ -837,3 +948,8 @@ double bUnit_GetScaler(const void *usys_pt, int index)
{
return ((bUnitCollection *)usys_pt)->units[index].scalar;
}
+
+bool bUnit_IsSuppressed(const void *usys_pt, int index)
+{
+ return (((bUnitCollection *)usys_pt)->units[index].flag & B_UNIT_DEF_SUPPRESS) != 0;
+}
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
new file mode 100644
index 00000000000..0b1f9d8bd24
--- /dev/null
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -0,0 +1,446 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/workspace.c
+ * \ingroup bke
+ */
+
+/* allow accessing private members of DNA_workspace_types.h */
+#define DNA_PRIVATE_WORKSPACE_ALLOW
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+#include "BLI_listbase.h"
+
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_object.h"
+#include "BKE_workspace.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_workspace_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "MEM_guardedalloc.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Internal utils */
+
+static void workspace_layout_name_set(
+ WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+{
+ BLI_strncpy(layout->name, new_name, sizeof(layout->name));
+ BLI_uniquename(&workspace->layouts, layout, "Layout", '.', offsetof(WorkSpaceLayout, name), sizeof(layout->name));
+}
+
+/**
+ * This should only be used directly when it is to be expected that there isn't
+ * a layout within \a workspace that wraps \a screen. Usually - especially outside
+ * of BKE_workspace - #BKE_workspace_layout_find should be used!
+ */
+static WorkSpaceLayout *workspace_layout_find_exec(
+ const WorkSpace *workspace, const bScreen *screen)
+{
+ return BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen));
+}
+
+static void workspace_relation_add(
+ ListBase *relation_list, void *parent, void *data)
+{
+ WorkSpaceDataRelation *relation = MEM_callocN(sizeof(*relation), __func__);
+ relation->parent = parent;
+ relation->value = data;
+ /* add to head, if we switch back to it soon we find it faster. */
+ BLI_addhead(relation_list, relation);
+}
+static void workspace_relation_remove(
+ ListBase *relation_list, WorkSpaceDataRelation *relation)
+{
+ BLI_remlink(relation_list, relation);
+ MEM_freeN(relation);
+}
+
+static void workspace_relation_ensure_updated(
+ ListBase *relation_list, void *parent, void *data)
+{
+ WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ relation->value = data;
+ /* reinsert at the head of the list, so that more commonly used relations are found faster. */
+ BLI_remlink(relation_list, relation);
+ BLI_addhead(relation_list, relation);
+ }
+ else {
+ /* no matching relation found, add new one */
+ workspace_relation_add(relation_list, parent, data);
+ }
+}
+
+static void *workspace_relation_get_data_matching_parent(
+ const ListBase *relation_list, const void *parent)
+{
+ WorkSpaceDataRelation *relation = BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
+ if (relation != NULL) {
+ return relation->value;
+ }
+ else {
+ return NULL;
+ }
+}
+
+/**
+ * Checks if \a screen is already used within any workspace. A screen should never be assigned to multiple
+ * WorkSpaceLayouts, but that should be ensured outside of the BKE_workspace module and without such checks.
+ * Hence, this should only be used as assert check before assigining a screen to a workspace.
+ */
+#ifndef NDEBUG
+static bool workspaces_is_screen_used
+#else
+static bool UNUSED_FUNCTION(workspaces_is_screen_used)
+#endif
+ (const Main *bmain, bScreen *screen)
+{
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if (workspace_layout_find_exec(workspace, screen)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* -------------------------------------------------------------------- */
+/* Create, delete, init */
+
+WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
+{
+ WorkSpace *new_workspace = BKE_libblock_alloc(bmain, ID_WS, name, 0);
+ return new_workspace;
+}
+
+/**
+ * The function that actually frees the workspace data (not workspace itself). It shouldn't be called
+ * directly, instead #BKE_workspace_remove should be, which calls this through #BKE_libblock_free then.
+ *
+ * Should something like a bke_internal.h be added, this should go there!
+ */
+void BKE_workspace_free(WorkSpace *workspace)
+{
+ BKE_workspace_relations_free(&workspace->hook_layout_relations);
+
+ BLI_freelistN(&workspace->owner_ids);
+ BLI_freelistN(&workspace->layouts);
+
+ while (!BLI_listbase_is_empty(&workspace->tools)) {
+ BKE_workspace_tool_remove(workspace, workspace->tools.first);
+ }
+
+ if (workspace->status_text) {
+ MEM_freeN(workspace->status_text);
+ workspace->status_text = NULL;
+ }
+}
+
+/**
+ * Remove \a workspace by freeing itself and its data. This is a higher-level wrapper that
+ * calls #BKE_workspace_free (through #BKE_libblock_free) to free the workspace data, and frees
+ * other data-blocks owned by \a workspace and its layouts (currently that is screens only).
+ *
+ * Always use this to remove (and free) workspaces. Don't free non-ID workspace members here.
+ */
+void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
+{
+ for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout; layout = layout_next) {
+ layout_next = layout->next;
+ BKE_workspace_layout_remove(bmain, workspace, layout);
+ }
+ BKE_libblock_free(bmain, workspace);
+}
+
+WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain)
+{
+ WorkSpaceInstanceHook *hook = MEM_callocN(sizeof(WorkSpaceInstanceHook), __func__);
+
+ /* set an active screen-layout for each possible window/workspace combination */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, workspace->layouts.first);
+ }
+
+ return hook;
+}
+void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *hook)
+{
+ /* workspaces should never be freed before wm (during which we call this function) */
+ BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces));
+
+ /* Free relations for this hook */
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
+ relation;
+ relation = relation_next)
+ {
+ relation_next = relation->next;
+ if (relation->parent == hook) {
+ workspace_relation_remove(&workspace->hook_layout_relations, relation);
+ }
+ }
+ }
+
+ MEM_freeN(hook);
+}
+
+/**
+ * Add a new layout to \a workspace for \a screen.
+ */
+WorkSpaceLayout *BKE_workspace_layout_add(
+ Main *bmain,
+ WorkSpace *workspace,
+ bScreen *screen,
+ const char *name)
+{
+ WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__);
+
+ BLI_assert(!workspaces_is_screen_used(bmain, screen));
+#ifndef DEBUG
+ UNUSED_VARS(bmain);
+#endif
+ layout->screen = screen;
+ id_us_plus(&layout->screen->id);
+ workspace_layout_name_set(workspace, layout, name);
+ BLI_addtail(&workspace->layouts, layout);
+
+ return layout;
+}
+
+void BKE_workspace_layout_remove(
+ Main *bmain,
+ WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ id_us_min(&layout->screen->id);
+ BKE_libblock_free(bmain, layout->screen);
+ BLI_freelinkN(&workspace->layouts, layout);
+}
+
+void BKE_workspace_relations_free(
+ ListBase *relation_list)
+{
+ for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation; relation = relation_next) {
+ relation_next = relation->next;
+ workspace_relation_remove(relation_list, relation);
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* General Utils */
+
+WorkSpaceLayout *BKE_workspace_layout_find(
+ const WorkSpace *workspace, const bScreen *screen)
+{
+ WorkSpaceLayout *layout = workspace_layout_find_exec(workspace, screen);
+ if (layout) {
+ return layout;
+ }
+
+ printf("%s: Couldn't find layout in this workspace: '%s' screen: '%s'. "
+ "This should not happen!\n",
+ __func__, workspace->id.name + 2, screen->id.name + 2);
+
+ return NULL;
+}
+
+/**
+ * Find the layout for \a screen without knowing which workspace to look in.
+ * Can also be used to find the workspace that contains \a screen.
+ *
+ * \param r_workspace: Optionally return the workspace that contains the looked up layout (if found).
+ */
+WorkSpaceLayout *BKE_workspace_layout_find_global(
+ const Main *bmain, const bScreen *screen,
+ WorkSpace **r_workspace)
+{
+ WorkSpaceLayout *layout;
+
+ if (r_workspace) {
+ *r_workspace = NULL;
+ }
+
+ for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ if ((layout = workspace_layout_find_exec(workspace, screen))) {
+ if (r_workspace) {
+ *r_workspace = workspace;
+ }
+
+ return layout;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Circular workspace layout iterator.
+ *
+ * \param callback: Custom function which gets executed for each layout. Can return false to stop iterating.
+ * \param arg: Custom data passed to each \a callback call.
+ *
+ * \return the layout at which \a callback returned false.
+ */
+WorkSpaceLayout *BKE_workspace_layout_iter_circular(
+ const WorkSpace *workspace, WorkSpaceLayout *start,
+ bool (*callback)(const WorkSpaceLayout *layout, void *arg),
+ void *arg, const bool iter_backward)
+{
+ WorkSpaceLayout *iter_layout;
+
+ if (iter_backward) {
+ LISTBASE_CIRCULAR_BACKWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start);
+ }
+ else {
+ LISTBASE_CIRCULAR_FORWARD_BEGIN(&workspace->layouts, iter_layout, start)
+ {
+ if (!callback(iter_layout, arg)) {
+ return iter_layout;
+ }
+ }
+ LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start)
+ }
+
+ return NULL;
+}
+
+void BKE_workspace_tool_remove(
+ struct WorkSpace *workspace, struct bToolRef *tref)
+{
+ if (tref->runtime) {
+ MEM_freeN(tref->runtime);
+ }
+ if (tref->properties) {
+ IDP_FreeProperty(tref->properties);
+ MEM_freeN(tref->properties);
+ }
+ BLI_remlink(&workspace->tools, tref);
+ MEM_freeN(tref);
+}
+
+/* -------------------------------------------------------------------- */
+/* Getters/Setters */
+
+WorkSpace *BKE_workspace_active_get(WorkSpaceInstanceHook *hook)
+{
+ return hook->active;
+}
+void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
+{
+ hook->active = workspace;
+ if (workspace) {
+ WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+ if (layout) {
+ hook->act_layout = layout;
+ }
+ }
+}
+
+WorkSpaceLayout *BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook)
+{
+ return hook->act_layout;
+}
+void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, WorkSpaceLayout *layout)
+{
+ hook->act_layout = layout;
+}
+
+bScreen *BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook)
+{
+ return hook->act_layout->screen;
+}
+void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace, bScreen *screen)
+{
+ /* we need to find the WorkspaceLayout that wraps this screen */
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(hook->active, screen);
+ BKE_workspace_hook_layout_for_workspace_set(hook, workspace, layout);
+}
+
+ListBase *BKE_workspace_layouts_get(WorkSpace *workspace)
+{
+ return &workspace->layouts;
+}
+
+const char *BKE_workspace_layout_name_get(const WorkSpaceLayout *layout)
+{
+ return layout->name;
+}
+void BKE_workspace_layout_name_set(WorkSpace *workspace, WorkSpaceLayout *layout, const char *new_name)
+{
+ workspace_layout_name_set(workspace, layout, new_name);
+}
+
+bScreen *BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout)
+{
+ return layout->screen;
+}
+void BKE_workspace_layout_screen_set(WorkSpaceLayout *layout, bScreen *screen)
+{
+ layout->screen = screen;
+}
+
+WorkSpaceLayout *BKE_workspace_hook_layout_for_workspace_get(
+ const WorkSpaceInstanceHook *hook, const WorkSpace *workspace)
+{
+ return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+}
+void BKE_workspace_hook_layout_for_workspace_set(
+ WorkSpaceInstanceHook *hook, WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ hook->act_layout = layout;
+ workspace_relation_ensure_updated(&workspace->hook_layout_relations, hook, layout);
+}
+
+bool BKE_workspace_owner_id_check(
+ const WorkSpace *workspace, const char *owner_id)
+{
+ if ((*owner_id == '\0') ||
+ ((workspace->flags & WORKSPACE_USE_FILTER_BY_ORIGIN) == 0))
+ {
+ return true;
+ }
+ else {
+ /* we could use hash lookup, for now this list is highly under < ~16 items. */
+ return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL;
+ }
+}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 545ca41c9c0..110b933e67c 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <stdlib.h>
#include <math.h>
+
#include "MEM_guardedalloc.h"
#include "DNA_world_types.h"
@@ -43,6 +44,7 @@
#include "BLI_listbase.h"
#include "BKE_animsys.h"
+#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@@ -51,18 +53,18 @@
#include "BKE_node.h"
#include "BKE_world.h"
+#include "DRW_engine.h"
+
+#include "DEG_depsgraph.h"
+
#include "GPU_material.h"
/** Free (or release) any data used by this world (does not free the world itself). */
void BKE_world_free(World *wrld)
{
- int a;
-
BKE_animdata_free((ID *)wrld, false);
- for (a = 0; a < MAX_MTEX; a++) {
- MEM_SAFE_FREE(wrld->mtex[a]);
- }
+ DRW_drawdata_free((ID *)wrld);
/* is no lib link block, but world extension */
if (wrld->nodetree) {
@@ -84,23 +86,9 @@ void BKE_world_init(World *wrld)
wrld->horr = 0.05f;
wrld->horg = 0.05f;
wrld->horb = 0.05f;
- wrld->zenr = 0.01f;
- wrld->zeng = 0.01f;
- wrld->zenb = 0.01f;
- wrld->skytype = 0;
-
- wrld->exp = 0.0f;
- wrld->exposure = wrld->range = 1.0f;
wrld->aodist = 10.0f;
- wrld->aosamp = 5;
wrld->aoenergy = 1.0f;
- wrld->ao_env_energy = 1.0f;
- wrld->ao_indirect_energy = 1.0f;
- wrld->ao_indirect_bounces = 1;
- wrld->aobias = 0.05f;
- wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY;
- wrld->ao_approx_error = 0.25f;
wrld->preview = NULL;
wrld->miststa = 5.0f;
@@ -128,12 +116,6 @@ World *BKE_world_add(Main *bmain, const char *name)
*/
void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, const int flag)
{
- for (int a = 0; a < MAX_MTEX; a++) {
- if (wrld_src->mtex[a]) {
- wrld_dst->mtex[a] = MEM_dupallocN(wrld_src->mtex[a]);
- }
- }
-
if (wrld_src->nodetree) {
/* Note: nodetree is *not* in bmain, however this specific case is handled at lower level
* (see BKE_libblock_copy_ex()). */
@@ -141,6 +123,7 @@ void BKE_world_copy_data(Main *bmain, World *wrld_dst, const World *wrld_src, co
}
BLI_listbase_clear(&wrld_dst->gpumaterial);
+ BLI_listbase_clear((ListBase *)&wrld_dst->drawdata);
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
BKE_previewimg_id_copy(&wrld_dst->id, &wrld_src->id);
@@ -167,23 +150,16 @@ World *BKE_world_localize(World *wrld)
* ... Once f*** nodes are fully converted to that too :( */
World *wrldn;
- int a;
wrldn = BKE_libblock_copy_nolib(&wrld->id, false);
- for (a = 0; a < MAX_MTEX; a++) {
- if (wrld->mtex[a]) {
- wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), __func__);
- memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex));
- }
- }
-
if (wrld->nodetree)
wrldn->nodetree = ntreeLocalize(wrld->nodetree);
wrldn->preview = NULL;
BLI_listbase_clear(&wrldn->gpumaterial);
+ BLI_listbase_clear((ListBase *)&wrldn->drawdata);
return wrldn;
}
@@ -192,3 +168,9 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
{
BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
}
+
+void BKE_world_eval(struct Depsgraph *depsgraph, World *world)
+{
+ DEG_debug_print_eval(depsgraph, __func__, world->id.name, world);
+ GPU_material_free(&world->gpumaterial);
+}
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 7e989b6588f..a1732b79ea3 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -43,6 +43,7 @@
#include "BLI_utildefines.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -84,10 +85,6 @@ static void context_free_avi(void *context_v);
# include "BKE_writeffmpeg.h"
#endif
-#ifdef WITH_FRAMESERVER
-# include "BKE_writeframeserver.h"
-#endif
-
bMovieHandle *BKE_movie_handle_get(const char imtype)
{
static bMovieHandle mh = {NULL};
@@ -121,16 +118,6 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
mh.context_free = BKE_ffmpeg_context_free;
}
#endif
-#ifdef WITH_FRAMESERVER
- if (imtype == R_IMF_IMTYPE_FRAMESERVER) {
- mh.start_movie = BKE_frameserver_start;
- mh.append_movie = BKE_frameserver_append;
- mh.end_movie = BKE_frameserver_end;
- mh.get_next_frame = BKE_frameserver_loop;
- mh.context_create = BKE_frameserver_context_create;
- mh.context_free = BKE_frameserver_context_free;
- }
-#endif
/* in case all above are disabled */
(void)imtype;
@@ -211,8 +198,6 @@ static int start_avi(void *context_v, Scene *UNUSED(scene), RenderData *rd, int
avi->interlace = 0;
avi->odd_fields = 0;
-/* avi->interlace = rd->mode & R_FIELDS; */
-/* avi->odd_fields = (rd->mode & R_ODDFIELD) ? 1 : 0; */
printf("Created avi: %s\n", name);
return 1;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 68083b499f3..06f11301acb 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -45,8 +45,8 @@
#include "BLI_blenlib.h"
#ifdef WITH_AUDASPACE
-# include AUD_DEVICE_H
-# include AUD_SPECIAL_H
+# include <AUD_Device.h>
+# include <AUD_Special.h>
#endif
#include "BLI_utildefines.h"
@@ -54,6 +54,7 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_sound.h"
@@ -326,10 +327,6 @@ static int write_video_frame(FFMpegContext *context, RenderData *rd, int cfra, A
frame->pts = cfra;
- if (rd->mode & R_FIELDS) {
- frame->top_field_first = ((rd->mode & R_ODDFIELD) != 0);
- }
-
ret = avcodec_encode_video2(c, &packet, frame, &got_output);
if (ret >= 0 && got_output) {
@@ -611,14 +608,6 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
}
-#if 0
- /* this options are not set in ffmpeg.c and leads to artifacts with MPEG-4
- * see #33586: Encoding to mpeg4 makes first frame(s) blocky
- */
- c->rc_initial_buffer_occupancy = rd->ffcodecdata.rc_buffer_size * 3 / 4;
- c->rc_buffer_aggressivity = 1.0;
-#endif
-
/* Deprecated and not doing anything since July 2015, deleted in recent ffmpeg */
//c->me_method = ME_EPZS;
@@ -674,25 +663,11 @@ static AVStream *alloc_video_stream(FFMpegContext *context, RenderData *rd, int
}
}
- if ((of->oformat->flags & AVFMT_GLOBALHEADER)
-#if 0
- || STREQ(of->oformat->name, "mp4")
- || STREQ(of->oformat->name, "mov")
- || STREQ(of->oformat->name, "3gp")
-#endif
- )
- {
+ if ((of->oformat->flags & AVFMT_GLOBALHEADER)) {
PRINT("Using global header\n");
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
- /* Determine whether we are encoding interlaced material or not */
- if (rd->mode & R_FIELDS) {
- PRINT("Encoding interlaced video\n");
- c->flags |= CODEC_FLAG_INTERLACED_DCT;
- c->flags |= CODEC_FLAG_INTERLACED_ME;
- }
-
/* xasp & yasp got float lately... */
st->sample_aspect_ratio = c->sample_aspect_ratio = av_d2q(((double) rd->xasp / (double) rd->yasp), 255);
@@ -1306,12 +1281,6 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
{
PRINT("Closing ffmpeg...\n");
-#if 0
- if (context->audio_stream) { /* SEE UPPER */
- write_audio_frames(context);
- }
-#endif
-
#ifdef WITH_AUDASPACE
if (is_autosplit == false) {
if (context->audio_mixdown_device) {
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
deleted file mode 100644
index ebd6de6009e..00000000000
--- a/source/blender/blenkernel/intern/writeframeserver.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright (c) 2006 Peter Schlaile
- *
- * Contributor(s):
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/writeframeserver.c
- * \ingroup bke
- *
- * Frameserver
- * Makes Blender accessible from TMPGenc directly using VFAPI (you can
- * use firefox too ;-)
- */
-
-#ifdef WITH_FRAMESERVER
-
-#include <string.h>
-#include <stdio.h>
-
-#if defined(_WIN32)
-#include <winsock2.h>
-#include <windows.h>
-#include <winbase.h>
-#include <direct.h>
-#else
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netdb.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#endif
-
-#include <stdlib.h>
-
-#include "DNA_userdef_types.h"
-
-#include "BLI_utildefines.h"
-
-#include "BKE_writeframeserver.h"
-#include "BKE_global.h"
-#include "BKE_report.h"
-
-#include "DNA_scene_types.h"
-#include "MEM_guardedalloc.h"
-
-typedef struct FrameserverContext {
- int sock;
- int connsock;
- int write_ppm;
- int render_width;
- int render_height;
-} FrameserverContext;
-
-
-#if defined(_WIN32)
-static int startup_socket_system(void)
-{
- WSADATA wsa;
- return (WSAStartup(MAKEWORD(2, 0), &wsa) == 0);
-}
-
-static void shutdown_socket_system(void)
-{
- WSACleanup();
-}
-static int select_was_interrupted_by_signal(void)
-{
- return (WSAGetLastError() == WSAEINTR);
-}
-#else
-static int startup_socket_system(void)
-{
- return 1;
-}
-
-static void shutdown_socket_system(void)
-{
-}
-
-static int select_was_interrupted_by_signal(void)
-{
- return (errno == EINTR);
-}
-
-static int closesocket(int fd)
-{
- return close(fd);
-}
-#endif
-
-int BKE_frameserver_start(void *context_v, struct Scene *scene, RenderData *UNUSED(rd), int rectx, int recty, ReportList *reports, bool UNUSED(preview), const char *UNUSED(suffix))
-{
- struct sockaddr_in addr;
- int arg = 1;
- FrameserverContext *context = context_v;
-
- (void)scene; /* unused */
-
- if (!startup_socket_system()) {
- BKE_report(reports, RPT_ERROR, "Cannot startup socket system");
- return 0;
- }
-
- if ((context->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- shutdown_socket_system();
- BKE_report(reports, RPT_ERROR, "Cannot open socket");
- return 0;
- }
-
- setsockopt(context->sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(arg));
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(U.frameserverport);
- addr.sin_addr.s_addr = INADDR_ANY;
-
- if (bind(context->sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- shutdown_socket_system();
- BKE_report(reports, RPT_ERROR, "Cannot bind to socket");
- return 0;
- }
-
- if (listen(context->sock, SOMAXCONN) < 0) {
- shutdown_socket_system();
- BKE_report(reports, RPT_ERROR, "Cannot establish listen backlog");
- return 0;
- }
- context->connsock = -1;
-
- context->render_width = rectx;
- context->render_height = recty;
-
- return 1;
-}
-
-static char index_page[] =
-"HTTP/1.1 200 OK\r\n"
-"Content-Type: text/html\r\n"
-"\r\n"
-"<html><head><title>Blender Frameserver</title></head>\n"
-"<body><pre>\n"
-"<H2>Blender Frameserver</H2>\n"
-"<A HREF=info.txt>Render Info</A><br>\n"
-"<A HREF=close.txt>Stop Rendering</A><br>\n"
-"\n"
-"Images can be found here\n"
-"\n"
-"images/ppm/%d.ppm\n"
-"\n"
-"</pre></body></html>\n";
-
-static char good_bye[] =
-"HTTP/1.1 200 OK\r\n"
-"Content-Type: text/html\r\n"
-"\r\n"
-"<html><head><title>Blender Frameserver</title></head>\n"
-"<body><pre>\n"
-"Render stopped. Goodbye</pre></body></html>";
-
-static int safe_write(const int connsock, char *s, int tosend)
-{
- int total = tosend;
- do {
- int got = send(connsock, s, tosend, 0);
- if (got < 0) {
- return got;
- }
- tosend -= got;
- s += got;
- } while (tosend > 0);
-
- return total;
-}
-
-static int safe_puts(const int connsock, char *s)
-{
- return safe_write(connsock, s, strlen(s));
-}
-
-static int handle_request(FrameserverContext *context, RenderData *rd, char *req)
-{
- char *p;
- char *path;
- int pathlen;
-
- if (memcmp(req, "GET ", 4) != 0) {
- return -1;
- }
-
- p = req + 4;
- path = p;
-
- while (*p != ' ' && *p) p++;
-
- *p = 0;
-
- if (STREQ(path, "/index.html") || STREQ(path, "/")) {
- safe_puts(context->connsock, index_page);
- return -1;
- }
-
- context->write_ppm = 0;
- pathlen = strlen(path);
-
- if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
- context->write_ppm = 1;
- return atoi(path + 12);
- }
- if (STREQ(path, "/info.txt")) {
- char buf[4096];
-
- sprintf(buf,
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html\r\n"
- "\r\n"
- "start %d\n"
- "end %d\n"
- "width %d\n"
- "height %d\n"
- "rate %d\n"
- "ratescale %d\n",
- rd->sfra,
- rd->efra,
- context->render_width,
- context->render_height,
- rd->frs_sec,
- 1
- );
-
- safe_puts(context->connsock, buf);
- return -1;
- }
- if (STREQ(path, "/close.txt")) {
- safe_puts(context->connsock, good_bye);
- G.is_break = true; /* Abort render */
- return -1;
- }
- return -1;
-}
-
-int BKE_frameserver_loop(void *context_v, RenderData *rd, ReportList *UNUSED(reports))
-{
- fd_set readfds;
- struct timeval tv;
- struct sockaddr_in addr;
- int len, rval;
- unsigned int socklen;
- char buf[4096];
-
- FrameserverContext *context = context_v;
-
- if (context->connsock != -1) {
- closesocket(context->connsock);
- context->connsock = -1;
- }
-
- tv.tv_sec = 1;
- tv.tv_usec = 0;
-
- FD_ZERO(&readfds);
- FD_SET(context->sock, &readfds);
-
- rval = select(context->sock + 1, &readfds, NULL, NULL, &tv);
- if (rval < 0) {
- return -1;
- }
-
- if (rval == 0) { /* nothing to be done */
- return -1;
- }
-
- socklen = sizeof(addr);
-
- if ((context->connsock = accept(context->sock, (struct sockaddr *)&addr, &socklen)) < 0) {
- return -1;
- }
-
- FD_ZERO(&readfds);
- FD_SET(context->connsock, &readfds);
-
- for (;;) {
- /* give 10 seconds for telnet testing... */
- tv.tv_sec = 10;
- tv.tv_usec = 0;
-
- rval = select(context->connsock + 1, &readfds, NULL, NULL, &tv);
- if (rval > 0) {
- break;
- }
- else if (rval == 0) {
- return -1;
- }
- else if (rval < 0) {
- if (!select_was_interrupted_by_signal()) {
- return -1;
- }
- }
- }
-
- len = recv(context->connsock, buf, sizeof(buf) - 1, 0);
-
- if (len < 0) {
- return -1;
- }
-
- buf[len] = 0;
-
- return handle_request(context, rd, buf);
-}
-
-static void serve_ppm(FrameserverContext *context, int *pixels, int rectx, int recty)
-{
- unsigned char *rendered_frame;
- unsigned char *row = (unsigned char *) malloc(context->render_width * 3);
- int y;
- char header[1024];
-
- sprintf(header,
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: image/ppm\r\n"
- "Connection: close\r\n"
- "\r\n"
- "P6\n"
- "# Creator: blender frameserver v0.0.1\n"
- "%d %d\n"
- "255\n",
- rectx, recty);
-
- safe_puts(context->connsock, header);
-
- rendered_frame = (unsigned char *)pixels;
-
- for (y = recty - 1; y >= 0; y--) {
- unsigned char *target = row;
- unsigned char *src = rendered_frame + rectx * 4 * y;
- unsigned char *end = src + rectx * 4;
- while (src != end) {
- target[2] = src[2];
- target[1] = src[1];
- target[0] = src[0];
-
- target += 3;
- src += 4;
- }
- safe_write(context->connsock, (char *)row, 3 * rectx);
- }
- free(row);
- closesocket(context->connsock);
- context->connsock = -1;
-}
-
-int BKE_frameserver_append(void *context_v, RenderData *UNUSED(rd), int UNUSED(start_frame), int frame, int *pixels,
- int rectx, int recty, const char *UNUSED(suffix), ReportList *UNUSED(reports))
-{
- FrameserverContext *context = context_v;
-
- fprintf(stderr, "Serving frame: %d\n", frame);
- if (context->write_ppm) {
- serve_ppm(context, pixels, rectx, recty);
- }
- if (context->connsock != -1) {
- closesocket(context->connsock);
- context->connsock = -1;
- }
-
- return 1;
-}
-
-void BKE_frameserver_end(void *context_v)
-{
- FrameserverContext *context = context_v;
-
- if (context->connsock != -1) {
- closesocket(context->connsock);
- context->connsock = -1;
- }
- closesocket(context->sock);
- shutdown_socket_system();
-}
-
-void *BKE_frameserver_context_create(void)
-{
- FrameserverContext *context = MEM_mallocN(sizeof(FrameserverContext), "Frameserver Context");
- return context;
-}
-
-void BKE_frameserver_context_free(void *context_v)
-{
- FrameserverContext *context = context_v;
- if (context) {
- MEM_freeN(context);
- }
-}
-
-#endif /* WITH_FRAMESERVER */
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
index 71937531dac..67728445f3a 100644
--- a/source/blender/blenkernel/nla_private.h
+++ b/source/blender/blenkernel/nla_private.h
@@ -33,6 +33,10 @@
#ifndef __NLA_PRIVATE_H__
#define __NLA_PRIVATE_H__
+struct Depsgraph;
+
+#include "RNA_types.h"
+
/* --------------- NLA Evaluation DataTypes ----------------------- */
/* used for list of strips to accumulate at current time */
@@ -66,9 +70,11 @@ enum eNlaEvalStrip_StripMode {
typedef struct NlaEvalChannel {
struct NlaEvalChannel *next, *prev;
- PointerRNA ptr; /* pointer to struct containing property to use */
- PropertyRNA *prop; /* RNA-property type to use (should be in the struct given) */
- int index; /* array index (where applicable) */
+ /* RNA reference to use with pointer and index */
+ PathResolvedRNA rna;
+
+ /* Original parameters used to look up the reference for write_orig_anim_rna */
+ const char *rna_path;
float value; /* value of this channel */
} NlaEvalChannel;
@@ -81,8 +87,8 @@ float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode);
/* --------------- NLA Evaluation (very-private stuff) ----------------------- */
/* these functions are only defined here to avoid problems with the order in which they get defined... */
-NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime);
-void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes);
-void nladata_flush_channels(ListBase *channels);
+NlaEvalStrip *nlastrips_ctime_get_strip(struct Depsgraph *depsgraph, ListBase *list, ListBase *strips, short index, float ctime);
+void nlastrip_evaluate(struct Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes);
+void nladata_flush_channels(struct Depsgraph *depsgraph, PointerRNA *ptr, ListBase *channels);
#endif /* __NLA_PRIVATE_H__ */