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:
authorBastien Montagne <montagne29@wanadoo.fr>2016-07-25 20:33:55 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-07-25 20:33:55 +0300
commitbcc020b1bc1b60f6cbd6d2c9bf400744931e57e1 (patch)
treefef4d83d0e5addb59c8389adf125281a4c7e35f8
parent99bb1accbbb8e1ba38f30b073b22deb107bf3220 (diff)
parent3f36cd3f33e52d53d82a3a221e2a576cf26390a5 (diff)
Merge branch 'asset-engine' into asset-experimentsasset-experiments
Conflicts: source/blender/blenloader/intern/readfile.c
-rw-r--r--.gitmodules4
-rw-r--r--CMakeLists.txt39
-rw-r--r--GNUmakefile24
-rw-r--r--build_files/cmake/macros.cmake61
-rw-r--r--extern/curve_fit_nd/CMakeLists.txt6
-rw-r--r--extern/curve_fit_nd/curve_fit_nd.h35
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic.c33
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic_refit.c1420
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_inline.h2
-rw-r--r--extern/curve_fit_nd/intern/generic_alloc_impl.h220
-rw-r--r--extern/curve_fit_nd/intern/generic_heap.c278
-rw-r--r--extern/curve_fit_nd/intern/generic_heap.h54
-rw-r--r--intern/atomic/intern/atomic_ops_utils.h4
-rw-r--r--intern/audaspace/Python/AUD_PyAPI.cpp2
-rw-r--r--intern/cycles/blender/addon/properties.py5
-rw-r--r--intern/cycles/blender/addon/ui.py5
-rw-r--r--intern/cycles/blender/blender_mesh.cpp45
-rw-r--r--intern/cycles/blender/blender_object.cpp10
-rw-r--r--intern/cycles/blender/blender_sync.cpp1
-rw-r--r--intern/cycles/blender/blender_sync.h4
-rw-r--r--intern/cycles/blender/blender_util.h17
-rw-r--r--intern/cycles/bvh/bvh.cpp10
-rw-r--r--intern/cycles/device/device_opencl.cpp79
-rw-r--r--intern/cycles/kernel/bvh/bvh_shadow_all.h2
-rw-r--r--intern/cycles/kernel/bvh/bvh_volume_all.h4
-rw-r--r--intern/cycles/kernel/bvh/qbvh_shadow_all.h2
-rw-r--r--intern/cycles/kernel/bvh/qbvh_volume_all.h4
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h79
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h40
-rw-r--r--intern/cycles/kernel/closure/bsdf_util.h2
-rw-r--r--intern/cycles/kernel/geom/geom_motion_triangle.h6
-rw-r--r--intern/cycles/kernel/geom/geom_triangle_intersect.h35
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h24
-rw-r--r--intern/cycles/kernel/kernel_shadow.h7
-rw-r--r--intern/cycles/kernel/kernel_types.h17
-rw-r--r--intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h2
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h10
-rw-r--r--intern/cycles/render/CMakeLists.txt2
-rw-r--r--intern/cycles/render/constant_fold.cpp122
-rw-r--r--intern/cycles/render/constant_fold.h59
-rw-r--r--intern/cycles/render/graph.cpp56
-rw-r--r--intern/cycles/render/graph.h8
-rw-r--r--intern/cycles/render/integrator.cpp2
-rw-r--r--intern/cycles/render/mesh.cpp6
-rw-r--r--intern/cycles/render/nodes.cpp314
-rw-r--r--intern/cycles/render/nodes.h45
-rw-r--r--intern/cycles/render/object.cpp2
-rw-r--r--intern/cycles/render/scene.cpp8
-rw-r--r--intern/cycles/render/scene.h4
-rw-r--r--intern/cycles/util/util_math_fast.h3
-rw-r--r--intern/ghost/GHOST_Types.h2
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp9
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.cpp2
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp3
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp31
-rw-r--r--intern/guardedalloc/test/simpletest/memtest.c1
-rw-r--r--intern/libmv/intern/autotrack.cc8
-rw-r--r--intern/libmv/libmv/multiview/projection.h2
-rw-r--r--intern/libmv/libmv/numeric/numeric.cc2
-rw-r--r--intern/libmv/libmv/numeric/numeric.h2
-rw-r--r--intern/opensubdiv/CMakeLists.txt2
-rw-r--r--intern/opensubdiv/gpu_shader_opensubd_display.glsl6
-rw-r--r--intern/opensubdiv/opensubdiv_capi.cc89
-rw-r--r--intern/opensubdiv/opensubdiv_capi.h11
-rw-r--r--intern/opensubdiv/opensubdiv_converter.cc112
-rw-r--r--intern/opensubdiv/opensubdiv_converter_capi.h16
-rw-r--r--intern/opensubdiv/opensubdiv_gpu_capi.cc414
-rw-r--r--intern/opensubdiv/opensubdiv_topology_refiner.h41
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py6
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py2
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py5
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_lightmap.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py15
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py2
-rw-r--r--release/scripts/startup/bl_ui/space_info.py33
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py2
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py4
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py2
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py3
-rw-r--r--source/blender/blenfont/intern/blf_font.c8
-rw-r--r--source/blender/blenkernel/BKE_action.h2
-rw-r--r--source/blender/blenkernel/BKE_armature.h3
-rw-r--r--source/blender/blenkernel/BKE_asset_engine.h (renamed from source/blender/blenkernel/BKE_asset.h)11
-rw-r--r--source/blender/blenkernel/BKE_brush.h2
-rw-r--r--source/blender/blenkernel/BKE_camera.h2
-rw-r--r--source/blender/blenkernel/BKE_curve.h2
-rw-r--r--source/blender/blenkernel/BKE_font.h2
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h2
-rw-r--r--source/blender/blenkernel/BKE_group.h1
-rw-r--r--source/blender/blenkernel/BKE_icons.h4
-rw-r--r--source/blender/blenkernel/BKE_image.h2
-rw-r--r--source/blender/blenkernel/BKE_key.h1
-rw-r--r--source/blender/blenkernel/BKE_lamp.h2
-rw-r--r--source/blender/blenkernel/BKE_lattice.h2
-rw-r--r--source/blender/blenkernel/BKE_library.h6
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h2
-rw-r--r--source/blender/blenkernel/BKE_mask.h2
-rw-r--r--source/blender/blenkernel/BKE_material.h10
-rw-r--r--source/blender/blenkernel/BKE_mball.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h15
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/BKE_object.h4
-rw-r--r--source/blender/blenkernel/BKE_particle.h2
-rw-r--r--source/blender/blenkernel/BKE_scene.h2
-rw-r--r--source/blender/blenkernel/BKE_sound.h2
-rw-r--r--source/blender/blenkernel/BKE_speaker.h2
-rw-r--r--source/blender/blenkernel/BKE_text.h1
-rw-r--r--source/blender/blenkernel/BKE_texture.h2
-rw-r--r--source/blender/blenkernel/BKE_world.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt5
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h4
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_intern.h7
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c15
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c244
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_util.c2
-rw-r--r--source/blender/blenkernel/intern/action.c34
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c10
-rw-r--r--source/blender/blenkernel/intern/armature.c50
-rw-r--r--source/blender/blenkernel/intern/armature_update.c4
-rw-r--r--source/blender/blenkernel/intern/asset_engine.c (renamed from source/blender/blenkernel/intern/asset.c)15
-rw-r--r--source/blender/blenkernel/intern/blender.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c2
-rw-r--r--source/blender/blenkernel/intern/brush.c19
-rw-r--r--source/blender/blenkernel/intern/camera.c38
-rw-r--r--source/blender/blenkernel/intern/colortools.c3
-rw-r--r--source/blender/blenkernel/intern/constraint.c2
-rw-r--r--source/blender/blenkernel/intern/curve.c37
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c16
-rw-r--r--source/blender/blenkernel/intern/font.c5
-rw-r--r--source/blender/blenkernel/intern/gpencil.c5
-rw-r--r--source/blender/blenkernel/intern/group.c10
-rw-r--r--source/blender/blenkernel/intern/icons.c75
-rw-r--r--source/blender/blenkernel/intern/image.c113
-rw-r--r--source/blender/blenkernel/intern/key.c17
-rw-r--r--source/blender/blenkernel/intern/lamp.c38
-rw-r--r--source/blender/blenkernel/intern/lattice.c37
-rw-r--r--source/blender/blenkernel/intern/library.c479
-rw-r--r--source/blender/blenkernel/intern/library_asset.c269
-rw-r--r--source/blender/blenkernel/intern/library_query.c16
-rw-r--r--source/blender/blenkernel/intern/library_remap.c8
-rw-r--r--source/blender/blenkernel/intern/linestyle.c10
-rw-r--r--source/blender/blenkernel/intern/mask.c10
-rw-r--r--source/blender/blenkernel/intern/material.c60
-rw-r--r--source/blender/blenkernel/intern/mball.c34
-rw-r--r--source/blender/blenkernel/intern/mesh.c58
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c185
-rw-r--r--source/blender/blenkernel/intern/modifier.c2
-rw-r--r--source/blender/blenkernel/intern/node.c37
-rw-r--r--source/blender/blenkernel/intern/object.c30
-rw-r--r--source/blender/blenkernel/intern/object_update.c11
-rw-r--r--source/blender/blenkernel/intern/packedFile.c6
-rw-r--r--source/blender/blenkernel/intern/particle.c34
-rw-r--r--source/blender/blenkernel/intern/scene.c11
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c44
-rw-r--r--source/blender/blenkernel/intern/sequencer.c36
-rw-r--r--source/blender/blenkernel/intern/sound.c5
-rw-r--r--source/blender/blenkernel/intern/speaker.c34
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c126
-rw-r--r--source/blender/blenkernel/intern/text.c10
-rw-r--r--source/blender/blenkernel/intern/texture.c39
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c32
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c6
-rw-r--r--source/blender/blenkernel/intern/world.c36
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c3
-rw-r--r--source/blender/blenlib/BLI_threads.h2
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c128
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c2
-rw-r--r--source/blender/blenloader/intern/readfile.c41
-rw-r--r--source/blender/blenloader/intern/readfile.h2
-rw-r--r--source/blender/blenloader/intern/versioning_270.c23
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c5
-rw-r--r--source/blender/blenloader/intern/writefile.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c223
-rw-r--r--source/blender/bmesh/operators/bmo_connect_nonplanar.c18
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c4
-rw-r--r--source/blender/bmesh/operators/bmo_normals.c2
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c3
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c8
-rw-r--r--source/blender/collada/DocumentImporter.cpp36
-rw-r--r--source/blender/collada/EffectExporter.cpp7
-rw-r--r--source/blender/collada/ErrorHandler.cpp2
-rw-r--r--source/blender/collada/collada_utils.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MaskOperation.cpp1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc19
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc16
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc3
-rw-r--r--source/blender/depsgraph/intern/nodes/deg_node.cc5
-rw-r--r--source/blender/editors/armature/armature_utils.c12
-rw-r--r--source/blender/editors/curve/editcurve.c2
-rw-r--r--source/blender/editors/curve/editcurve_paint.c93
-rw-r--r--source/blender/editors/curve/editcurve_select.c19
-rw-r--r--source/blender/editors/curve/editfont.c2
-rw-r--r--source/blender/editors/include/ED_keyframing.h8
-rw-r--r--source/blender/editors/include/ED_view3d.h2
-rw-r--r--source/blender/editors/interface/interface.c2
-rw-r--r--source/blender/editors/interface/interface_draw.c54
-rw-r--r--source/blender/editors/interface/interface_handlers.c170
-rw-r--r--source/blender/editors/interface/interface_icons.c31
-rw-r--r--source/blender/editors/interface/interface_ops.c2
-rw-r--r--source/blender/editors/interface/interface_regions.c12
-rw-r--r--source/blender/editors/interface/interface_templates.c4
-rw-r--r--source/blender/editors/io/io_collada.c2
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c8
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/object/object_group.c2
-rw-r--r--source/blender/editors/object/object_relations.c12
-rw-r--r--source/blender/editors/object/object_select.c1
-rw-r--r--source/blender/editors/object/object_vgroup.c6
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/render/render_shading.c8
-rw-r--r--source/blender/editors/screen/area.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c29
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c25
-rw-r--r--source/blender/editors/sound/sound_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_editor.c2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c2
-rw-r--r--source/blender/editors/space_file/file_ops.c2
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_file/filelist.h2
-rw-r--r--source/blender/editors/space_file/space_file.c2
-rw-r--r--source/blender/editors/space_graph/graph_draw.c2
-rw-r--r--source/blender/editors/space_image/image_buttons.c71
-rw-r--r--source/blender/editors/space_image/image_ops.c175
-rw-r--r--source/blender/editors/space_node/node_relationships.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c26
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c5
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c32
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h1
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c55
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c68
-rw-r--r--source/blender/editors/transform/transform_conversions.c8
-rw-r--r--source/blender/editors/transform/transform_snap_object.c1324
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.cpp2
-rw-r--r--source/blender/freestyle/intern/view_map/Functions1D.cpp2
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c21
-rw-r--r--source/blender/gpu/intern/gpu_draw.c2
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c7
-rw-r--r--source/blender/gpu/intern/gpu_material.c6
-rw-r--r--source/blender/gpu/intern/gpu_shader.c4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl10
-rw-r--r--source/blender/imbuf/intern/filter.c2
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c4
-rw-r--r--source/blender/makesdna/DNA_ID.h5
-rw-r--r--source/blender/makesdna/DNA_brush_types.h9
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h2
-rw-r--r--source/blender/makesdna/DNA_color_types.h3
-rw-r--r--source/blender/makesdna/DNA_genfile.h9
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h16
-rw-r--r--source/blender/makesdna/DNA_scene_types.h10
-rw-r--r--source/blender/makesdna/DNA_sdna_types.h2
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h2
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c131
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt3
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c7
-rw-r--r--source/blender/makesrna/intern/rna_access.c14
-rw-r--r--source/blender/makesrna/intern/rna_animation.c23
-rw-r--r--source/blender/makesrna/intern/rna_armature.c4
-rw-r--r--source/blender/makesrna/intern/rna_asset.c3
-rw-r--r--source/blender/makesrna/intern/rna_camera.c4
-rw-r--r--source/blender/makesrna/intern/rna_color.c3
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c24
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c38
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c10
-rw-r--r--source/blender/makesrna/intern/rna_space.c6
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c36
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c7
-rw-r--r--source/blender/python/bmesh/bmesh_py_api.c9
-rw-r--r--source/blender/python/generic/idprop_py_api.c2
-rw-r--r--source/blender/python/generic/py_capi_utils.c10
-rw-r--r--source/blender/python/intern/bpy_app.c12
-rw-r--r--source/blender/python/intern/bpy_driver.c9
-rw-r--r--source/blender/python/intern/bpy_library_load.c60
-rw-r--r--source/blender/python/intern/bpy_operator.c11
-rw-r--r--source/blender/python/intern/bpy_props.c32
-rw-r--r--source/blender/python/intern/bpy_rna.c166
-rw-r--r--source/blender/python/intern/bpy_rna.h2
-rw-r--r--source/blender/python/intern/gpu.c4
-rw-r--r--source/blender/python/mathutils/mathutils.c10
-rw-r--r--source/blender/quicktime/apple/qtkit_import.m2
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h34
-rw-r--r--source/blender/render/intern/include/render_types.h1
-rw-r--r--source/blender/render/intern/include/rendercore.h2
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp8
-rw-r--r--source/blender/render/intern/source/convertblender.c6
-rw-r--r--source/blender/render/intern/source/occlusion.c11
-rw-r--r--source/blender/render/intern/source/pipeline.c20
-rw-r--r--source/blender/render/intern/source/rayshade.c14
-rw-r--r--source/blender/render/intern/source/render_texture.c3
-rw-r--r--source/blender/render/intern/source/renderdatabase.c4
-rw-r--r--source/blender/render/intern/source/sss.c14
-rw-r--r--source/blender/render/intern/source/zbuf.c9
-rw-r--r--source/blender/windowmanager/WM_api.h2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c2
-rw-r--r--source/blender/windowmanager/intern/wm_files.c10
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c156
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c2
-rw-r--r--source/blenderplayer/CMakeLists.txt2
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c4
-rw-r--r--source/creator/CMakeLists.txt4
-rw-r--r--source/creator/creator.c6
-rw-r--r--source/creator/creator_args.c19
-rw-r--r--source/gameengine/GameLogic/SCA_PythonController.cpp4
-rw-r--r--source/gameengine/GameLogic/SCA_PythonKeyboard.cpp26
-rw-r--r--source/gameengine/GameLogic/SCA_PythonMouse.cpp31
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp2
m---------source/tools0
323 files changed, 7196 insertions, 3468 deletions
diff --git a/.gitmodules b/.gitmodules
index 132f6cffada..0b8228e3f14 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -10,3 +10,7 @@
path = release/datafiles/locale
url = ../blender-translations.git
ignore = all
+[submodule "source/tools"]
+ path = source/tools
+ url = ../blender-dev-tools.git
+ ignore = all
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1c933d38ab9..1dfa838a5a2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1283,11 +1283,21 @@ elseif(WIN32)
if(MSVC)
# Minimum MSVC Version
- set(_min_ver "18.0.31101")
- if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver})
- message(FATAL_ERROR
- "Visual Studio 2013 (Update 4, ${_min_ver}) required, "
- "found (${CMAKE_CXX_COMPILER_VERSION})")
+ if(MSVC_VERSION EQUAL 1800)
+ set(_min_ver "18.0.31101")
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver})
+ message(FATAL_ERROR
+ "Visual Studio 2013 (Update 4, ${_min_ver}) required, "
+ "found (${CMAKE_CXX_COMPILER_VERSION})")
+ endif()
+ endif()
+ if(MSVC_VERSION EQUAL 1900)
+ set(_min_ver "19.0.24210")
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver})
+ message(FATAL_ERROR
+ "Visual Studio 2015 (Update 3, ${_min_ver}) required, "
+ "found (${CMAKE_CXX_COMPILER_VERSION})")
+ endif()
endif()
unset(_min_ver)
@@ -1353,17 +1363,6 @@ elseif(WIN32)
set(PLATFORM_LINKFLAGS_DEBUG "/IGNORE:4099 /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libc.lib")
- # Use dynamic loading for OpenMP
- if(WITH_OPENMP)
- if(MSVC_VERSION EQUAL 1800)
- set(OPENMP_DLL_NAME "vcomp120")
- else()
- set(OPENMP_DLL_NAME "vcomp140")
- endif()
- set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
- set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
- endif()
-
if(NOT DEFINED LIBDIR)
# Setup 64bit and 64bit windows systems
@@ -3162,6 +3161,14 @@ add_subdirectory(tests)
# CPack for generating packages
include(build_files/cmake/packaging.cmake)
+#-----------------------------------------------------------------------------
+# Use dynamic loading for OpenMP
+if(WITH_BLENDER)
+ openmp_delayload(blender)
+endif(WITH_BLENDER)
+if(WITH_PLAYER)
+ openmp_delayload(blenderplayer)
+endif(WITH_PLAYER)
#-----------------------------------------------------------------------------
# Print Final Configuration
diff --git a/GNUmakefile b/GNUmakefile
index d9c895c214a..1fda1a25a92 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -182,14 +182,20 @@ help: .FORCE
@echo " * package_archive - build an archive package"
@echo ""
@echo "Testing Targets (not associated with building blender)"
- @echo " * test - run ctest, currently tests import/export, operator execution and that python modules load"
- @echo " * test_cmake - runs our own cmake file checker which detects errors in the cmake file list definitions"
- @echo " * test_pep8 - checks all python script are pep8 which are tagged to use the stricter formatting"
+ @echo " * test - run ctest, currently tests import/export,"
+ @echo " operator execution and that python modules load"
+ @echo " * test_cmake - runs our own cmake file checker"
+ @echo " which detects errors in the cmake file list definitions"
+ @echo " * test_pep8 - checks all python script are pep8"
+ @echo " which are tagged to use the stricter formatting"
@echo " * test_deprecated - checks for deprecation tags in our code which may need to be removed"
- @echo " * test_style_c - checks C/C++ conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
+ @echo " * test_style_c - checks C/C++ conforms with blenders style guide:"
+ @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
@echo " * test_style_c_qtc - same as test_style but outputs QtCreator tasks format"
- @echo " * test_style_osl - checks OpenShadingLanguage conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
- @echo " * test_style_osl_qtc - checks OpenShadingLanguage conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
+ @echo " * test_style_osl - checks OpenShadingLanguage conforms with blenders style guide:"
+ @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
+ @echo " * test_style_osl_qtc - checks OpenShadingLanguage conforms with blenders style guide:"
+ @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle"
@echo ""
@echo "Static Source Code Checking (not associated with building blender)"
@echo " * check_cppcheck - run blender source through cppcheck (C & C++)"
@@ -405,7 +411,8 @@ update: .FORCE
# Simple version of ./doc/python_api/sphinx_doc_gen.sh with no PDF generation.
doc_py: .FORCE
- "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup --python doc/python_api/sphinx_doc_gen.py
+ "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup \
+ --python doc/python_api/sphinx_doc_gen.py
cd doc/python_api ; sphinx-build -b html sphinx-in sphinx-out
@echo "docs written into: '$(BLENDER_DIR)/doc/python_api/sphinx-out/contents.html'"
@@ -414,7 +421,8 @@ doc_doxy: .FORCE
@echo "docs written into: '$(BLENDER_DIR)/doc/doxygen/html/index.html'"
doc_dna: .FORCE
- "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup --python doc/blender_file_format/BlendFileDnaExporter_25.py
+ "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup \
+ --python doc/blender_file_format/BlendFileDnaExporter_25.py
@echo "docs written into: '$(BLENDER_DIR)/doc/blender_file_format/dna.html'"
doc_man: .FORCE
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index d29f086069a..f57a6952164 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -196,8 +196,33 @@ function(blender_source_group
endfunction()
+# Support per-target CMake flags
+# Read from: CMAKE_C_FLAGS_**** (made upper case) when set.
+#
+# 'name' should alway match the target name,
+# use this macro before add_library or add_executable.
+#
+# Optionally takes an arg passed to set(), eg PARENT_SCOPE.
+macro(add_cc_flags_custom_test
+ name
+ )
+
+ string(TOUPPER ${name} _name_upper)
+ if(DEFINED CMAKE_C_FLAGS_${_name_upper})
+ message(STATUS "Using custom CFLAGS: CMAKE_C_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${_name_upper}}" ${ARGV1})
+ endif()
+ if(DEFINED CMAKE_CXX_FLAGS_${_name_upper})
+ message(STATUS "Using custom CXXFLAGS: CMAKE_CXX_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${_name_upper}}" ${ARGV1})
+ endif()
+ unset(_name_upper)
+
+endmacro()
+
+
# only MSVC uses SOURCE_GROUP
-function(blender_add_lib_nolist
+function(blender_add_lib__impl
name
sources
includes
@@ -225,6 +250,18 @@ function(blender_add_lib_nolist
endfunction()
+function(blender_add_lib_nolist
+ name
+ sources
+ includes
+ includes_sys
+ )
+
+ add_cc_flags_custom_test(${name} PARENT_SCOPE)
+
+ blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}")
+endfunction()
+
function(blender_add_lib
name
sources
@@ -232,7 +269,9 @@ function(blender_add_lib
includes_sys
)
- blender_add_lib_nolist(${name} "${sources}" "${includes}" "${includes_sys}")
+ add_cc_flags_custom_test(${name} PARENT_SCOPE)
+
+ blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}")
set_property(GLOBAL APPEND PROPERTY BLENDER_LINK_LIBS ${name})
endfunction()
@@ -1508,3 +1547,21 @@ function(print_all_vars)
message("${_var}=${${_var}}")
endforeach()
endfunction()
+
+macro(openmp_delayload
+ projectname
+ )
+ if(MSVC)
+ if(WITH_OPENMP)
+ if(MSVC_VERSION EQUAL 1800)
+ set(OPENMP_DLL_NAME "vcomp120")
+ else()
+ set(OPENMP_DLL_NAME "vcomp140")
+ endif()
+ SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELEASE "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_DEBUG "/DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
+ SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_MINSIZEREL "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
+ endif(WITH_OPENMP)
+ endif(MSVC)
+endmacro()
diff --git a/extern/curve_fit_nd/CMakeLists.txt b/extern/curve_fit_nd/CMakeLists.txt
index 6669971aa2d..cc9efe1c470 100644
--- a/extern/curve_fit_nd/CMakeLists.txt
+++ b/extern/curve_fit_nd/CMakeLists.txt
@@ -26,10 +26,14 @@ set(INC_SYS
set(SRC
intern/curve_fit_cubic.c
+ intern/curve_fit_cubic_refit.c
intern/curve_fit_corners_detect.c
- intern/curve_fit_inline.h
curve_fit_nd.h
+ intern/curve_fit_inline.h
+ intern/generic_alloc_impl.h
+ intern/generic_heap.c
+ intern/generic_heap.h
)
blender_add_lib(extern_curve_fit_nd "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/extern/curve_fit_nd/curve_fit_nd.h b/extern/curve_fit_nd/curve_fit_nd.h
index 3649802a425..cfb1881fe00 100644
--- a/extern/curve_fit_nd/curve_fit_nd.h
+++ b/extern/curve_fit_nd/curve_fit_nd.h
@@ -86,6 +86,7 @@ int curve_fit_cubic_to_points_fl(
*
* \param points, points_len: The array of points to calculate a cubics from.
* \param dims: The number of dimensions for for each element in \a points.
+ * \param points_length_cache: Optional pre-calculated lengths between points.
* \param error_threshold: the error threshold to allow for,
* \param tan_l, tan_r: Normalized tangents the handles will be aligned to.
* Note that tangents must both point along the direction of the \a points,
@@ -98,6 +99,7 @@ int curve_fit_cubic_to_points_fl(
int curve_fit_cubic_to_points_single_db(
const double *points,
const unsigned int points_len,
+ const double *points_length_cache,
const unsigned int dims,
const double error_threshold,
const double tan_l[],
@@ -110,6 +112,7 @@ int curve_fit_cubic_to_points_single_db(
int curve_fit_cubic_to_points_single_fl(
const float *points,
const unsigned int points_len,
+ const float *points_length_cache,
const unsigned int dims,
const float error_threshold,
const float tan_l[],
@@ -121,8 +124,40 @@ int curve_fit_cubic_to_points_single_fl(
enum {
CURVE_FIT_CALC_HIGH_QUALIY = (1 << 0),
+ CURVE_FIT_CALC_CYCLIC = (1 << 1),
};
+
+/* curve_fit_cubic_refit.c */
+
+int curve_fit_cubic_to_points_refit_db(
+ const double *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const double error_threshold,
+ const unsigned int calc_flag,
+ const unsigned int *corners,
+ unsigned int corners_len,
+ const double corner_angle,
+
+ double **r_cubic_array, unsigned int *r_cubic_array_len,
+ unsigned int **r_cubic_orig_index,
+ unsigned int **r_corner_index_array, unsigned int *r_corner_index_len);
+
+int curve_fit_cubic_to_points_refit_fl(
+ const float *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const float error_threshold,
+ const unsigned int calc_flag,
+ const unsigned int *corners,
+ unsigned int corners_len,
+ const float corner_angle,
+
+ float **r_cubic_array, unsigned int *r_cubic_array_len,
+ unsigned int **r_cubic_orig_index,
+ unsigned int **r_corner_index_array, unsigned int *r_corner_index_len);
+
/* curve_fit_corners_detect.c */
/**
diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic.c b/extern/curve_fit_nd/intern/curve_fit_cubic.c
index 1a0f7dcfdee..24b216d32ff 100644
--- a/extern/curve_fit_nd/intern/curve_fit_cubic.c
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic.c
@@ -474,7 +474,7 @@ static double points_calc_circumference_factor(
* We could try support this but will likely cause extreme >1 scales which could cause other issues. */
// assert(angle >= len_tangent);
double factor = (angle / len_tangent);
- assert(factor < (M_PI / 2) + DBL_EPSILON);
+ assert(factor < (M_PI / 2) + (DBL_EPSILON * 10));
return factor;
}
else {
@@ -876,7 +876,6 @@ static double points_calc_coord_length(
#ifdef USE_LENGTH_CACHE
length = points_length_cache[i];
-
assert(len_vnvn(pt, pt_prev, dims) == points_length_cache[i]);
#else
length = len_vnvn(pt, pt_prev, dims);
@@ -1435,6 +1434,7 @@ int curve_fit_cubic_to_points_fl(
int curve_fit_cubic_to_points_single_db(
const double *points,
const uint points_len,
+ const double *points_length_cache,
const uint dims,
const double error_threshold,
const double tan_l[],
@@ -1451,10 +1451,14 @@ int curve_fit_cubic_to_points_single_db(
/* in this instance theres no advantage in using length cache,
* since we're not recursively calculating values. */
#ifdef USE_LENGTH_CACHE
- double *points_length_cache = malloc(sizeof(double) * points_len);
- points_calc_coord_length_cache(
- points, points_len, dims,
- points_length_cache);
+ double *points_length_cache_alloc = NULL;
+ if (points_length_cache == NULL) {
+ points_length_cache_alloc = malloc(sizeof(double) * points_len);
+ points_calc_coord_length_cache(
+ points, points_len, dims,
+ points_length_cache_alloc);
+ points_length_cache = points_length_cache_alloc;
+ }
#endif
fit_cubic_to_points(
@@ -1467,7 +1471,9 @@ int curve_fit_cubic_to_points_single_db(
cubic, r_error_max_sq, &split_index);
#ifdef USE_LENGTH_CACHE
- free(points_length_cache);
+ if (points_length_cache_alloc) {
+ free(points_length_cache_alloc);
+ }
#endif
copy_vnvn(r_handle_l, CUBIC_PT(cubic, 1, dims), dims);
@@ -1479,6 +1485,7 @@ int curve_fit_cubic_to_points_single_db(
int curve_fit_cubic_to_points_single_fl(
const float *points,
const uint points_len,
+ const float *points_length_cache,
const uint dims,
const float error_threshold,
const float tan_l[],
@@ -1490,9 +1497,15 @@ int curve_fit_cubic_to_points_single_fl(
{
const uint points_flat_len = points_len * dims;
double *points_db = malloc(sizeof(double) * points_flat_len);
+ double *points_length_cache_db = NULL;
copy_vndb_vnfl(points_db, points, points_flat_len);
+ if (points_length_cache) {
+ points_length_cache_db = malloc(sizeof(double) * points_len);
+ copy_vndb_vnfl(points_length_cache_db, points_length_cache, points_len);
+ }
+
#ifdef USE_VLA
double tan_l_db[dims];
double tan_r_db[dims];
@@ -1510,7 +1523,7 @@ int curve_fit_cubic_to_points_single_fl(
copy_vndb_vnfl(tan_r_db, tan_r, dims);
int result = curve_fit_cubic_to_points_single_db(
- points_db, points_len, dims,
+ points_db, points_len, points_length_cache_db, dims,
(double)error_threshold,
tan_l_db, tan_r_db,
r_handle_l_db, r_handle_r_db,
@@ -1518,6 +1531,10 @@ int curve_fit_cubic_to_points_single_fl(
free(points_db);
+ if (points_length_cache_db) {
+ free(points_length_cache_db);
+ }
+
copy_vnfl_vndb(r_handle_l, r_handle_l_db, dims);
copy_vnfl_vndb(r_handle_r, r_handle_r_db, dims);
*r_error_sq = (float)r_error_sq_db;
diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
new file mode 100644
index 00000000000..46445467869
--- /dev/null
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
@@ -0,0 +1,1420 @@
+/*
+ * Copyright (c) 2016, Campbell Barton.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Curve Re-fitting Method
+ * =======================
+ *
+ * This is a more processor intensive method of fitting,
+ * compared to #curve_fit_cubic_to_points_db, and works as follows:
+ *
+ * - First iteratively remove all points under the error threshold.
+ * - If corner calculation is enabled:
+ * - Find adjacent knots that exceed the angle limit
+ * - Find a 'split' point between the knots (could include the knots)
+ * - If copying the tangents to this split point doesn't exceed the error threshold:
+ * - Assign the tangents of the two knots to the split point, define it as a corner.
+ * (after this, we have many points which are too close).
+ * - Run a re-fit pass, where knots are re-positioned between their adjacent knots
+ * when their re-fit position has a lower 'error'.
+ * While re-fitting, remove knots that fall below the error threshold.
+ */
+
+#include <math.h>
+#include <float.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+typedef unsigned int uint;
+
+#include "curve_fit_inline.h"
+#include "../curve_fit_nd.h"
+
+#include "generic_heap.h"
+
+#ifdef _MSC_VER
+# define alloca(size) _alloca(size)
+#endif
+
+#if !defined(_MSC_VER)
+# define USE_VLA
+#endif
+
+#ifdef USE_VLA
+# ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wvla"
+# endif
+#else
+# ifdef __GNUC__
+# pragma GCC diagnostic error "-Wvla"
+# endif
+#endif
+
+/* adjust the knots after simplifying */
+#define USE_KNOT_REFIT
+/* remove knots under the error threshold while re-fitting */
+#define USE_KNOT_REFIT_REMOVE
+/* detect corners over an angle threshold */
+#define USE_CORNER_DETECT
+/* avoid re-calculating lengths multiple times */
+#define USE_LENGTH_CACHE
+/* use pool allocator */
+#define USE_TPOOL
+
+
+#define SPLIT_POINT_INVALID ((uint)-1)
+
+#define MAX2(x, y) ((x) > (y) ? (x) : (y))
+
+#define SQUARE(a) ((a) * (a))
+
+#ifdef __GNUC__
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+# define UNLIKELY(x) (x)
+#endif
+
+struct PointData {
+ const double *points;
+ uint points_len;
+#ifdef USE_LENGTH_CACHE
+ const double *points_length_cache;
+#endif
+};
+
+struct Knot {
+ struct Knot *next, *prev;
+
+ HeapNode *heap_node;
+
+ /**
+ * Currently the same, access as different for now
+ * since we may want to support different point/knot indices
+ */
+ uint index;
+
+ uint can_remove : 1;
+ uint is_removed : 1;
+ uint is_corner : 1;
+
+ double handles[2];
+ /**
+ * Store the error value, to see if we can improve on it
+ * (without having to re-calculate each time)
+ *
+ * This is the error between this knot and the next */
+ double error_sq_next;
+
+ /* Initially point to contiguous memory, however we may re-assign */
+ double *tan[2];
+} Knot;
+
+
+struct KnotRemoveState {
+ uint index;
+ /* Handles for prev/next knots */
+ double handles[2];
+};
+
+#ifdef USE_TPOOL
+/* rstate_* pool allocator */
+#define TPOOL_IMPL_PREFIX rstate
+#define TPOOL_ALLOC_TYPE struct KnotRemoveState
+#define TPOOL_STRUCT ElemPool_KnotRemoveState
+#include "generic_alloc_impl.h"
+#undef TPOOL_IMPL_PREFIX
+#undef TPOOL_ALLOC_TYPE
+#undef TPOOL_STRUCT
+#endif /* USE_TPOOL */
+
+#ifdef USE_KNOT_REFIT
+struct KnotRefitState {
+ uint index;
+ /** When SPLIT_POINT_INVALID - remove this item */
+ uint index_refit;
+ /** Handles for prev/next knots */
+ double handles_prev[2], handles_next[2];
+ double error_sq[2];
+};
+
+#ifdef USE_TPOOL
+/* refit_* pool allocator */
+#define TPOOL_IMPL_PREFIX refit
+#define TPOOL_ALLOC_TYPE struct KnotRefitState
+#define TPOOL_STRUCT ElemPool_KnotRefitState
+#include "generic_alloc_impl.h"
+#undef TPOOL_IMPL_PREFIX
+#undef TPOOL_ALLOC_TYPE
+#undef TPOOL_STRUCT
+#endif /* USE_TPOOL */
+#endif /* USE_KNOT_REFIT */
+
+
+#ifdef USE_CORNER_DETECT
+/** Result of collapsing a corner. */
+struct KnotCornerState {
+ uint index;
+ /* Merge adjacent handles into this one (may be shared with the 'index') */
+ uint index_adjacent[2];
+
+ /* Handles for prev/next knots */
+ double handles_prev[2], handles_next[2];
+ double error_sq[2];
+};
+
+/* refit_* pool allocator */
+#ifdef USE_TPOOL
+#define TPOOL_IMPL_PREFIX corner
+#define TPOOL_ALLOC_TYPE struct KnotCornerState
+#define TPOOL_STRUCT ElemPool_KnotCornerState
+#include "generic_alloc_impl.h"
+#undef TPOOL_IMPL_PREFIX
+#undef TPOOL_ALLOC_TYPE
+#undef TPOOL_STRUCT
+#endif /* USE_TPOOL */
+#endif /* USE_CORNER_DETECT */
+
+
+/* Utility functions */
+
+#ifdef USE_KNOT_REFIT
+/**
+ * Find the most distant point between the 2 knots.
+ */
+static uint knot_find_split_point(
+ const struct PointData *pd,
+ const struct Knot *knot_l, const struct Knot *knot_r,
+ const uint knots_len,
+ const uint dims)
+{
+ uint split_point = SPLIT_POINT_INVALID;
+ double split_point_dist_best = -DBL_MAX;
+
+ const double *offset = &pd->points[knot_l->index * dims];
+
+#ifdef USE_VLA
+ double v_plane[dims];
+ double v_proj[dims];
+ double v_offset[dims];
+#else
+ double *v_plane = alloca(sizeof(double) * dims);
+ double *v_proj = alloca(sizeof(double) * dims);
+ double *v_offset = alloca(sizeof(double) * dims);
+#endif
+
+ sub_vn_vnvn(
+ v_plane,
+ &pd->points[knot_l->index * dims],
+ &pd->points[knot_r->index * dims],
+ dims);
+
+ normalize_vn(v_plane, dims);
+
+ const uint knots_end = knots_len - 1;
+ const struct Knot *k_step = knot_l;
+ do {
+ if (k_step->index != knots_end) {
+ k_step += 1;
+ }
+ else {
+ /* wrap around */
+ k_step = k_step - knots_end;
+ }
+
+ if (k_step != knot_r) {
+ sub_vn_vnvn(v_offset, &pd->points[k_step->index * dims], offset, dims);
+ project_plane_vn_vnvn_normalized(v_proj, v_offset, v_plane, dims);
+
+ double split_point_dist_test = len_squared_vn(v_proj, dims);
+ if (split_point_dist_test > split_point_dist_best) {
+ split_point_dist_best = split_point_dist_test;
+ split_point = k_step->index;
+ }
+ }
+ else {
+ break;
+ }
+
+ } while (true);
+
+ return split_point;
+}
+#endif /* USE_KNOT_REFIT */
+
+
+#ifdef USE_CORNER_DETECT
+/**
+ * Find the knot furthest from the line between \a knot_l & \a knot_r.
+ * This is to be used as a split point.
+ */
+static uint knot_find_split_point_on_axis(
+ const struct PointData *pd,
+ const struct Knot *knot_l, const struct Knot *knot_r,
+ const uint knots_len,
+ const double *plane_no,
+ const uint dims)
+{
+ uint split_point = SPLIT_POINT_INVALID;
+ double split_point_dist_best = -DBL_MAX;
+
+ const uint knots_end = knots_len - 1;
+ const struct Knot *k_step = knot_l;
+ do {
+ if (k_step->index != knots_end) {
+ k_step += 1;
+ }
+ else {
+ /* wrap around */
+ k_step = k_step - knots_end;
+ }
+
+ if (k_step != knot_r) {
+ double split_point_dist_test = dot_vnvn(plane_no, &pd->points[k_step->index * dims], dims);
+ if (split_point_dist_test > split_point_dist_best) {
+ split_point_dist_best = split_point_dist_test;
+ split_point = k_step->index;
+ }
+ }
+ else {
+ break;
+ }
+
+ } while (true);
+
+ return split_point;
+}
+#endif /* USE_CORNER_DETECT */
+
+
+static double knot_remove_error_value(
+ const double *tan_l, const double *tan_r,
+ const double *points_offset, const uint points_offset_len,
+ const double *points_offset_length_cache,
+ const uint dims,
+ /* Avoid having to re-calculate again */
+ double r_handle_factors[2])
+{
+ double error_sq = FLT_MAX;
+
+#ifdef USE_VLA
+ double handle_factor_l[dims];
+ double handle_factor_r[dims];
+#else
+ double *handle_factor_l = alloca(sizeof(double) * dims);
+ double *handle_factor_r = alloca(sizeof(double) * dims);
+#endif
+
+ curve_fit_cubic_to_points_single_db(
+ points_offset, points_offset_len, points_offset_length_cache, dims, 0.0,
+ tan_l, tan_r,
+ handle_factor_l, handle_factor_r,
+ &error_sq);
+
+ assert(error_sq != FLT_MAX);
+
+ isub_vnvn(handle_factor_l, points_offset, dims);
+ r_handle_factors[0] = dot_vnvn(tan_l, handle_factor_l, dims);
+
+ isub_vnvn(handle_factor_r, &points_offset[(points_offset_len - 1) * dims], dims);
+ r_handle_factors[1] = dot_vnvn(tan_r, handle_factor_r, dims);
+
+ return error_sq;
+}
+
+static double knot_calc_curve_error_value(
+ const struct PointData *pd,
+ const struct Knot *knot_l, const struct Knot *knot_r,
+ const double *tan_l, const double *tan_r,
+ const uint dims,
+ double r_handle_factors[2])
+{
+ const uint points_offset_len = ((knot_l->index < knot_r->index) ?
+ (knot_r->index - knot_l->index) :
+ ((knot_r->index + pd->points_len) - knot_l->index)) + 1;
+
+ if (points_offset_len != 2) {
+ return knot_remove_error_value(
+ tan_l, tan_r,
+ &pd->points[knot_l->index * dims], points_offset_len,
+#ifdef USE_LENGTH_CACHE
+ &pd->points_length_cache[knot_l->index],
+#else
+ NULL,
+#endif
+ dims,
+ r_handle_factors);
+ }
+ else {
+ /* No points between, use 1/3 handle length with no error as a fallback. */
+ assert(points_offset_len == 2);
+#ifdef USE_LENGTH_CACHE
+ r_handle_factors[0] = r_handle_factors[1] = pd->points_length_cache[knot_l->index] / 3.0;
+#else
+ r_handle_factors[0] = r_handle_factors[1] = len_vnvn(
+ &pd->points[(knot_l->index + 0) * dims],
+ &pd->points[(knot_l->index + 1) * dims], dims) / 3.0;
+#endif
+ return 0.0;
+ }
+}
+
+struct KnotRemove_Params {
+ Heap *heap;
+ const struct PointData *pd;
+#ifdef USE_TPOOL
+ struct ElemPool_KnotRemoveState *epool;
+#endif
+};
+
+static void knot_remove_error_recalculate(
+ struct KnotRemove_Params *p,
+ struct Knot *k, const double error_sq_max,
+ const uint dims)
+{
+ assert(k->can_remove);
+ double handles[2];
+
+ const double cost_sq = knot_calc_curve_error_value(
+ p->pd, k->prev, k->next,
+ k->prev->tan[1], k->next->tan[0],
+ dims,
+ handles);
+
+ if (cost_sq < error_sq_max) {
+ struct KnotRemoveState *r;
+ if (k->heap_node) {
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+ }
+ else {
+#ifdef USE_TPOOL
+ r = rstate_pool_elem_alloc(p->epool);
+#else
+ r = malloc(sizeof(*r));
+#endif
+
+ r->index = k->index;
+ }
+
+ r->handles[0] = handles[0];
+ r->handles[1] = handles[1];
+
+ k->heap_node = HEAP_insert(p->heap, cost_sq, r);
+ }
+ else {
+ if (k->heap_node) {
+ struct KnotRemoveState *r;
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+
+#ifdef USE_TPOOL
+ rstate_pool_elem_free(p->epool, r);
+#else
+ free(r);
+#endif
+
+ k->heap_node = NULL;
+ }
+ }
+}
+
+/**
+ * Return length after being reduced.
+ */
+static uint curve_incremental_simplify(
+ const struct PointData *pd,
+ struct Knot *knots, const uint knots_len, uint knots_len_remaining,
+ double error_sq_max, const uint dims)
+{
+
+#ifdef USE_TPOOL
+ struct ElemPool_KnotRemoveState epool;
+
+ rstate_pool_create(&epool, 0);
+#endif
+
+ Heap *heap = HEAP_new(knots_len);
+
+ struct KnotRemove_Params params = {
+ .pd = pd,
+ .heap = heap,
+#ifdef USE_TPOOL
+ .epool = &epool,
+#endif
+ };
+
+ for (uint i = 0; i < knots_len; i++) {
+ struct Knot *k = &knots[i];
+ if (k->can_remove && (k->is_removed == false) && (k->is_corner == false)) {
+ knot_remove_error_recalculate(&params, k, error_sq_max, dims);
+ }
+ }
+
+ while (HEAP_is_empty(heap) == false) {
+ struct Knot *k;
+
+ {
+ const double error_sq = HEAP_top_value(heap);
+ struct KnotRemoveState *r = HEAP_popmin(heap);
+ k = &knots[r->index];
+ k->heap_node = NULL;
+ k->prev->handles[1] = r->handles[0];
+ k->next->handles[0] = r->handles[1];
+
+ k->prev->error_sq_next = error_sq;
+
+#ifdef USE_TPOOL
+ rstate_pool_elem_free(&epool, r);
+#else
+ free(r);
+#endif
+ }
+
+ if (UNLIKELY(knots_len_remaining <= 2)) {
+ continue;
+ }
+
+ struct Knot *k_prev = k->prev;
+ struct Knot *k_next = k->next;
+
+ /* Remove ourselves */
+ k_next->prev = k_prev;
+ k_prev->next = k_next;
+
+ k->next = NULL;
+ k->prev = NULL;
+ k->is_removed = true;
+
+ if (k_prev->can_remove && (k_prev->is_corner == false) && (k_prev->prev && k_prev->next)) {
+ knot_remove_error_recalculate(&params, k_prev, error_sq_max, dims);
+ }
+
+ if (k_next->can_remove && (k_next->is_corner == false) && (k_next->prev && k_next->next)) {
+ knot_remove_error_recalculate(&params, k_next, error_sq_max, dims);
+ }
+
+ knots_len_remaining -= 1;
+ }
+
+#ifdef USE_TPOOL
+ rstate_pool_destroy(&epool);
+#endif
+
+ HEAP_free(heap, free);
+
+ return knots_len_remaining;
+}
+
+
+#ifdef USE_KNOT_REFIT
+
+struct KnotRefit_Params {
+ Heap *heap;
+ const struct PointData *pd;
+#ifdef USE_TPOOL
+ struct ElemPool_KnotRefitState *epool;
+#endif
+};
+
+static void knot_refit_error_recalculate(
+ struct KnotRefit_Params *p,
+ struct Knot *knots, const uint knots_len,
+ struct Knot *k,
+ const double error_sq_max,
+ const uint dims)
+{
+ assert(k->can_remove);
+
+#ifdef USE_KNOT_REFIT_REMOVE
+ {
+ double handles[2];
+
+ /* First check if we can remove, this allows to refit and remove as we go. */
+ const double cost_sq = knot_calc_curve_error_value(
+ p->pd, k->prev, k->next,
+ k->prev->tan[1], k->next->tan[0],
+ dims,
+ handles);
+
+ if (cost_sq < error_sq_max) {
+ struct KnotRefitState *r;
+ if (k->heap_node) {
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+ }
+ else {
+#ifdef USE_TPOOL
+ r = refit_pool_elem_alloc(p->epool);
+#else
+ r = malloc(sizeof(*r));
+#endif
+ r->index = k->index;
+ }
+
+ r->index_refit = SPLIT_POINT_INVALID;
+
+ r->handles_prev[0] = handles[0];
+ r->handles_prev[1] = 0.0; /* unused */
+ r->handles_next[0] = 0.0; /* unused */
+ r->handles_next[1] = handles[1];
+
+ r->error_sq[0] = r->error_sq[1] = cost_sq;
+
+ /* Always perform removal before refitting, (make a negative number) */
+ k->heap_node = HEAP_insert(p->heap, cost_sq - error_sq_max, r);
+
+ return;
+ }
+ }
+#else
+ (void)error_sq_max;
+#endif /* USE_KNOT_REFIT_REMOVE */
+
+ const uint refit_index = knot_find_split_point(
+ p->pd, k->prev, k->next,
+ knots_len,
+ dims);
+
+ if ((refit_index == SPLIT_POINT_INVALID) ||
+ (refit_index == k->index))
+ {
+ goto remove;
+ }
+
+ struct Knot *k_refit = &knots[refit_index];
+
+ const double cost_sq_src_max = MAX2(k->prev->error_sq_next, k->error_sq_next);
+ assert(cost_sq_src_max <= error_sq_max);
+
+ double cost_sq_dst[2];
+ double handles_prev[2], handles_next[2];
+
+ if ((((cost_sq_dst[0] = knot_calc_curve_error_value(
+ p->pd, k->prev, k_refit,
+ k->prev->tan[1], k_refit->tan[0],
+ dims,
+ handles_prev)) < cost_sq_src_max) &&
+ ((cost_sq_dst[1] = knot_calc_curve_error_value(
+ p->pd, k_refit, k->next,
+ k_refit->tan[1], k->next->tan[0],
+ dims,
+ handles_next)) < cost_sq_src_max)))
+ {
+ {
+ struct KnotRefitState *r;
+ if (k->heap_node) {
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+ }
+ else {
+#ifdef USE_TPOOL
+ r = refit_pool_elem_alloc(p->epool);
+#else
+ r = malloc(sizeof(*r));
+#endif
+ r->index = k->index;
+ }
+
+ r->index_refit = refit_index;
+
+ r->handles_prev[0] = handles_prev[0];
+ r->handles_prev[1] = handles_prev[1];
+
+ r->handles_next[0] = handles_next[0];
+ r->handles_next[1] = handles_next[1];
+
+ r->error_sq[0] = cost_sq_dst[0];
+ r->error_sq[1] = cost_sq_dst[1];
+
+ const double cost_sq_dst_max = MAX2(cost_sq_dst[0], cost_sq_dst[1]);
+
+ assert(cost_sq_dst_max < cost_sq_src_max);
+
+ /* Weight for the greatest improvement */
+ k->heap_node = HEAP_insert(p->heap, cost_sq_src_max - cost_sq_dst_max, r);
+ }
+ }
+ else {
+remove:
+ if (k->heap_node) {
+ struct KnotRefitState *r;
+ r = HEAP_node_ptr(k->heap_node);
+ HEAP_remove(p->heap, k->heap_node);
+
+#ifdef USE_TPOOL
+ refit_pool_elem_free(p->epool, r);
+#else
+ free(r);
+#endif
+
+ k->heap_node = NULL;
+ }
+ }
+}
+
+/**
+ * Re-adjust the curves by re-fitting points.
+ * test the error from moving using points between the adjacent.
+ */
+static uint curve_incremental_simplify_refit(
+ const struct PointData *pd,
+ struct Knot *knots, const uint knots_len, uint knots_len_remaining,
+ const double error_sq_max,
+ const uint dims)
+{
+#ifdef USE_TPOOL
+ struct ElemPool_KnotRefitState epool;
+
+ refit_pool_create(&epool, 0);
+#endif
+
+ Heap *heap = HEAP_new(knots_len);
+
+ struct KnotRefit_Params params = {
+ .pd = pd,
+ .heap = heap,
+#ifdef USE_TPOOL
+ .epool = &epool,
+#endif
+ };
+
+ for (uint i = 0; i < knots_len; i++) {
+ struct Knot *k = &knots[i];
+ if (k->can_remove &&
+ (k->is_removed == false) &&
+ (k->is_corner == false) &&
+ (k->prev && k->next))
+ {
+ knot_refit_error_recalculate(&params, knots, knots_len, k, error_sq_max, dims);
+ }
+ }
+
+ while (HEAP_is_empty(heap) == false) {
+ struct Knot *k_old, *k_refit;
+
+ {
+ struct KnotRefitState *r = HEAP_popmin(heap);
+ k_old = &knots[r->index];
+ k_old->heap_node = NULL;
+
+#ifdef USE_KNOT_REFIT_REMOVE
+ if (r->index_refit == SPLIT_POINT_INVALID) {
+ k_refit = NULL;
+ }
+ else
+#endif
+ {
+ k_refit = &knots[r->index_refit];
+ k_refit->handles[0] = r->handles_prev[1];
+ k_refit->handles[1] = r->handles_next[0];
+ }
+
+ k_old->prev->handles[1] = r->handles_prev[0];
+ k_old->next->handles[0] = r->handles_next[1];
+
+#ifdef USE_TPOOL
+ refit_pool_elem_free(&epool, r);
+#else
+ free(r);
+#endif
+ }
+
+ if (UNLIKELY(knots_len_remaining <= 2)) {
+ continue;
+ }
+
+ struct Knot *k_prev = k_old->prev;
+ struct Knot *k_next = k_old->next;
+
+ k_old->next = NULL;
+ k_old->prev = NULL;
+ k_old->is_removed = true;
+
+#ifdef USE_KNOT_REFIT_REMOVE
+ if (k_refit == NULL) {
+ k_next->prev = k_prev;
+ k_prev->next = k_next;
+
+ knots_len_remaining -= 1;
+ }
+ else
+#endif
+ {
+ /* Remove ourselves */
+ k_next->prev = k_refit;
+ k_prev->next = k_refit;
+
+ k_refit->prev = k_prev;
+ k_refit->next = k_next;
+ k_refit->is_removed = false;
+ }
+
+ if (k_prev->can_remove && (k_prev->is_corner == false) && (k_prev->prev && k_prev->next)) {
+ knot_refit_error_recalculate(&params, knots, knots_len, k_prev, error_sq_max, dims);
+ }
+
+ if (k_next->can_remove && (k_next->is_corner == false) && (k_next->prev && k_next->next)) {
+ knot_refit_error_recalculate(&params, knots, knots_len, k_next, error_sq_max, dims);
+ }
+ }
+
+#ifdef USE_TPOOL
+ refit_pool_destroy(&epool);
+#endif
+
+ HEAP_free(heap, free);
+
+ return knots_len_remaining;
+}
+
+#endif /* USE_KNOT_REFIT */
+
+
+#ifdef USE_CORNER_DETECT
+
+struct KnotCorner_Params {
+ Heap *heap;
+ const struct PointData *pd;
+#ifdef USE_TPOOL
+ struct ElemPool_KnotCornerState *epool;
+#endif
+};
+
+/**
+ * (Re)calculate the error incurred from turning this into a corner.
+ */
+static void knot_corner_error_recalculate(
+ struct KnotCorner_Params *p,
+ struct Knot *k_split,
+ struct Knot *k_prev, struct Knot *k_next,
+ const double error_sq_max,
+ const uint dims)
+{
+ assert(k_prev->can_remove && k_next->can_remove);
+
+ double handles_prev[2], handles_next[2];
+ /* Test skipping 'k_prev' by using points (k_prev->prev to k_split) */
+ double cost_sq_dst[2];
+
+ if (((cost_sq_dst[0] = knot_calc_curve_error_value(
+ p->pd, k_prev, k_split,
+ k_prev->tan[1], k_prev->tan[1],
+ dims,
+ handles_prev)) < error_sq_max) &&
+ ((cost_sq_dst[1] = knot_calc_curve_error_value(
+ p->pd, k_split, k_next,
+ k_next->tan[0], k_next->tan[0],
+ dims,
+ handles_next)) < error_sq_max))
+ {
+ struct KnotCornerState *c;
+ if (k_split->heap_node) {
+ c = HEAP_node_ptr(k_split->heap_node);
+ HEAP_remove(p->heap, k_split->heap_node);
+ }
+ else {
+#ifdef USE_TPOOL
+ c = corner_pool_elem_alloc(p->epool);
+#else
+ c = malloc(sizeof(*c));
+#endif
+ c->index = k_split->index;
+ }
+
+ c->index_adjacent[0] = k_prev->index;
+ c->index_adjacent[1] = k_next->index;
+
+ /* Need to store handle lengths for both sides */
+ c->handles_prev[0] = handles_prev[0];
+ c->handles_prev[1] = handles_prev[1];
+
+ c->handles_next[0] = handles_next[0];
+ c->handles_next[1] = handles_next[1];
+
+ c->error_sq[0] = cost_sq_dst[0];
+ c->error_sq[1] = cost_sq_dst[1];
+
+ const double cost_max_sq = MAX2(cost_sq_dst[0], cost_sq_dst[1]);
+ k_split->heap_node = HEAP_insert(p->heap, cost_max_sq, c);
+ }
+ else {
+ if (k_split->heap_node) {
+ struct KnotCornerState *c;
+ c = HEAP_node_ptr(k_split->heap_node);
+ HEAP_remove(p->heap, k_split->heap_node);
+#ifdef USE_TPOOL
+ corner_pool_elem_free(p->epool, c);
+#else
+ free(c);
+#endif
+ k_split->heap_node = NULL;
+ }
+ }
+}
+
+
+/**
+ * Attempt to collapse close knots into corners,
+ * as long as they fall below the error threshold.
+ */
+static uint curve_incremental_simplify_corners(
+ const struct PointData *pd,
+ struct Knot *knots, const uint knots_len, uint knots_len_remaining,
+ const double error_sq_max, const double error_sq_2x_max,
+ const double corner_angle,
+ const uint dims,
+ uint *r_corner_index_len)
+{
+#ifdef USE_TPOOL
+ struct ElemPool_KnotCornerState epool;
+
+ corner_pool_create(&epool, 0);
+#endif
+
+ Heap *heap = HEAP_new(0);
+
+ struct KnotCorner_Params params = {
+ .pd = pd,
+ .heap = heap,
+#ifdef USE_TPOOL
+ .epool = &epool,
+#endif
+ };
+
+#ifdef USE_VLA
+ double plane_no[dims];
+ double k_proj_ref[dims];
+ double k_proj_split[dims];
+#else
+ double *plane_no = alloca(sizeof(double) * dims);
+ double *k_proj_ref = alloca(sizeof(double) * dims);
+ double *k_proj_split = alloca(sizeof(double) * dims);
+#endif
+
+ const double corner_angle_cos = cos(corner_angle);
+
+ uint corner_index_len = 0;
+
+ for (uint i = 0; i < knots_len; i++) {
+ if ((knots[i].is_removed == false) &&
+ (knots[i].can_remove == true) &&
+ (knots[i].next && knots[i].next->can_remove))
+ {
+ struct Knot *k_prev = &knots[i];
+ struct Knot *k_next = k_prev->next;
+
+ /* Angle outside threshold */
+ if (dot_vnvn(k_prev->tan[0], k_next->tan[1], dims) < corner_angle_cos) {
+ /* Measure distance projected onto a plane,
+ * since the points may be offset along their own tangents. */
+ sub_vn_vnvn(plane_no, k_next->tan[0], k_prev->tan[1], dims);
+
+ /* Compare 2x so as to allow both to be changed by maximum of error_sq_max */
+ const uint split_index = knot_find_split_point_on_axis(
+ pd, k_prev, k_next,
+ knots_len,
+ plane_no,
+ dims);
+
+ if (split_index != SPLIT_POINT_INVALID) {
+
+ project_vn_vnvn(k_proj_ref, &pd->points[k_prev->index * dims], k_prev->tan[1], dims);
+ project_vn_vnvn(k_proj_split, &pd->points[split_index * dims], k_prev->tan[1], dims);
+
+ if (len_squared_vnvn(k_proj_ref, k_proj_split, dims) < error_sq_2x_max) {
+
+ project_vn_vnvn(k_proj_ref, &pd->points[k_next->index * dims], k_next->tan[0], dims);
+ project_vn_vnvn(k_proj_split, &pd->points[split_index * dims], k_next->tan[0], dims);
+
+ if (len_squared_vnvn(k_proj_ref, k_proj_split, dims) < error_sq_2x_max) {
+
+ struct Knot *k_split = &knots[split_index];
+
+ knot_corner_error_recalculate(
+ &params,
+ k_split, k_prev, k_next,
+ error_sq_max,
+ dims);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ while (HEAP_is_empty(heap) == false) {
+ struct KnotCornerState *c = HEAP_popmin(heap);
+
+ struct Knot *k_split = &knots[c->index];
+
+ /* Remove while collapsing */
+ struct Knot *k_prev = &knots[c->index_adjacent[0]];
+ struct Knot *k_next = &knots[c->index_adjacent[1]];
+
+ /* Insert */
+ k_split->is_removed = false;
+ k_split->prev = k_prev;
+ k_split->next = k_next;
+ k_prev->next = k_split;
+ k_next->prev = k_split;
+
+ /* Update tangents */
+ k_split->tan[0] = k_prev->tan[1];
+ k_split->tan[1] = k_next->tan[0];
+
+ /* Own handles */
+ k_prev->handles[1] = c->handles_prev[0];
+ k_split->handles[0] = c->handles_prev[1];
+ k_split->handles[1] = c->handles_next[0];
+ k_next->handles[0] = c->handles_next[1];
+
+ k_prev->error_sq_next = c->error_sq[0];
+ k_split->error_sq_next = c->error_sq[1];
+
+ k_split->heap_node = NULL;
+
+#ifdef USE_TPOOL
+ corner_pool_elem_free(&epool, c);
+#else
+ free(c);
+#endif
+
+ k_split->is_corner = true;
+
+ knots_len_remaining++;
+
+ corner_index_len++;
+ }
+
+#ifdef USE_TPOOL
+ corner_pool_destroy(&epool);
+#endif
+
+ HEAP_free(heap, free);
+
+ *r_corner_index_len = corner_index_len;
+
+ return knots_len_remaining;
+}
+
+#endif /* USE_CORNER_DETECT */
+
+int curve_fit_cubic_to_points_refit_db(
+ const double *points,
+ const uint points_len,
+ const uint dims,
+ const double error_threshold,
+ const uint calc_flag,
+ const uint *corners,
+ const uint corners_len,
+ const double corner_angle,
+
+ double **r_cubic_array, uint *r_cubic_array_len,
+ uint **r_cubic_orig_index,
+ uint **r_corner_index_array, uint *r_corner_index_len)
+{
+ const uint knots_len = points_len;
+ struct Knot *knots = malloc(sizeof(Knot) * knots_len);
+ knots[0].next = NULL;
+
+#ifndef USE_CORNER_DETECT
+ (void)r_corner_index_array;
+ (void)r_corner_index_len;
+#endif
+
+(void)corners;
+(void)corners_len;
+
+ const bool is_cyclic = (calc_flag & CURVE_FIT_CALC_CYCLIC) != 0 && (points_len > 2);
+#ifdef USE_CORNER_DETECT
+ const bool use_corner = (corner_angle < M_PI);
+#else
+ (void)corner_angle;
+#endif
+
+ /* Over alloc the list x2 for cyclic curves,
+ * so we can evaluate across the start/end */
+ double *points_alloc = NULL;
+ if (is_cyclic) {
+ points_alloc = malloc((sizeof(double) * points_len * dims) * 2);
+ memcpy(points_alloc, points, sizeof(double) * points_len * dims);
+ memcpy(points_alloc + (points_len * dims), points_alloc, sizeof(double) * points_len * dims);
+ points = points_alloc;
+ }
+
+ double *tangents = malloc(sizeof(double) * knots_len * 2 * dims);
+
+ {
+ double *t_step = tangents;
+ for (uint i = 0; i < knots_len; i++) {
+ knots[i].next = (knots + i) + 1;
+ knots[i].prev = (knots + i) - 1;
+
+ knots[i].heap_node = NULL;
+ knots[i].index = i;
+ knots[i].index = i;
+ knots[i].can_remove = true;
+ knots[i].is_removed = false;
+ knots[i].is_corner = false;
+ knots[i].error_sq_next = 0.0;
+ knots[i].tan[0] = t_step; t_step += dims;
+ knots[i].tan[1] = t_step; t_step += dims;
+ }
+ assert(t_step == &tangents[knots_len * 2 * dims]);
+ }
+
+ if (is_cyclic) {
+ knots[0].prev = &knots[knots_len - 1];
+ knots[knots_len - 1].next = &knots[0];
+ }
+ else {
+ knots[0].prev = NULL;
+ knots[knots_len - 1].next = NULL;
+
+ /* always keep end-points */
+ knots[0].can_remove = false;
+ knots[knots_len - 1].can_remove = false;
+ }
+
+#ifdef USE_LENGTH_CACHE
+ double *points_length_cache = malloc(sizeof(double) * points_len * (is_cyclic ? 2 : 1));
+#endif
+
+ /* Initialize tangents,
+ * also set the values for knot handles since some may not collapse. */
+ {
+#ifdef USE_VLA
+ double tan_prev[dims];
+ double tan_next[dims];
+#else
+ double *tan_prev = alloca(sizeof(double) * dims);
+ double *tan_next = alloca(sizeof(double) * dims);
+#endif
+ double len_prev, len_next;
+
+#if 0
+ /* 2x normalize calculations, but correct */
+
+ for (uint i = 0; i < knots_len; i++) {
+ Knot *k = &knots[i];
+
+ if (k->prev) {
+ sub_vn_vnvn(tan_prev, &points[k->prev->index * dims], &points[k->index * dims], dims);
+#ifdef USE_LENGTH_CACHE
+ points_length_cache[i] =
+#endif
+ len_prev = normalize_vn(tan_prev, dims);
+ }
+ else {
+ zero_vn(tan_prev, dims);
+ len_prev = 0.0;
+ }
+
+ if (k->next) {
+ sub_vn_vnvn(tan_next, &points[k->index * dims], &points[k->next->index * dims], dims);
+ len_next = normalize_vn(tan_next, dims);
+ }
+ else {
+ zero_vn(tan_next, dims);
+ len_next = 0.0;
+ }
+
+ add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims);
+ normalize_vn(k->tan[0], dims);
+ copy_vnvn(k->tan[1], k->tan[0], dims);
+ k->handles[0] = len_prev / 3;
+ k->handles[1] = len_next / 3;
+ }
+#else
+ if (is_cyclic) {
+ len_prev = normalize_vn_vnvn(tan_prev, &points[(knots_len - 2) * dims], &points[(knots_len - 1) * dims], dims);
+ for (uint i_curr = knots_len - 1, i_next = 0; i_next < knots_len; i_curr = i_next++) {
+ struct Knot *k = &knots[i_curr];
+#ifdef USE_LENGTH_CACHE
+ points_length_cache[i_next] =
+#endif
+ len_next = normalize_vn_vnvn(tan_next, &points[i_curr * dims], &points[i_next * dims], dims);
+
+ add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims);
+ normalize_vn(k->tan[0], dims);
+ copy_vnvn(k->tan[1], k->tan[0], dims);
+ k->handles[0] = len_prev / 3;
+ k->handles[1] = len_next / 3;
+
+ copy_vnvn(tan_prev, tan_next, dims);
+ len_prev = len_next;
+ }
+ }
+ else {
+#ifdef USE_LENGTH_CACHE
+ points_length_cache[0] = 0.0;
+ points_length_cache[1] =
+#endif
+ len_prev = normalize_vn_vnvn(tan_prev, &points[0 * dims], &points[1 * dims], dims);
+ copy_vnvn(knots[0].tan[0], tan_prev, dims);
+ copy_vnvn(knots[0].tan[1], tan_prev, dims);
+ knots[0].handles[0] = len_prev / 3;
+ knots[0].handles[1] = len_prev / 3;
+
+ for (uint i_curr = 1, i_next = 2; i_next < knots_len; i_curr = i_next++) {
+ struct Knot *k = &knots[i_curr];
+
+#ifdef USE_LENGTH_CACHE
+ points_length_cache[i_next] =
+#endif
+ len_next = normalize_vn_vnvn(tan_next, &points[i_curr * dims], &points[i_next * dims], dims);
+
+ add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims);
+ normalize_vn(k->tan[0], dims);
+ copy_vnvn(k->tan[1], k->tan[0], dims);
+ k->handles[0] = len_prev / 3;
+ k->handles[1] = len_next / 3;
+
+ copy_vnvn(tan_prev, tan_next, dims);
+ len_prev = len_next;
+ }
+ copy_vnvn(knots[knots_len - 1].tan[0], tan_next, dims);
+ copy_vnvn(knots[knots_len - 1].tan[1], tan_next, dims);
+
+ knots[knots_len - 1].handles[0] = len_next / 3;
+ knots[knots_len - 1].handles[1] = len_next / 3;
+ }
+#endif
+ }
+
+#ifdef USE_LENGTH_CACHE
+ if (is_cyclic) {
+ memcpy(&points_length_cache[points_len], points_length_cache, sizeof(double) * points_len);
+ }
+#endif
+
+
+#if 0
+ for (uint i = 0; i < knots_len; i++) {
+ Knot *k = &knots[i];
+ printf("TAN %.8f %.8f %.8f %.8f\n", k->tan[0][0], k->tan[0][1], k->tan[1][0], k->tan[0][1]);
+ }
+#endif
+
+ const struct PointData pd = {
+ .points = points,
+ .points_len = points_len,
+#ifdef USE_LENGTH_CACHE
+ .points_length_cache = points_length_cache,
+#endif
+ };
+
+ uint knots_len_remaining = knots_len;
+
+ /* 'curve_incremental_simplify_refit' can be called here, but its very slow
+ * just remove all within the threshold first. */
+ knots_len_remaining = curve_incremental_simplify(
+ &pd, knots, knots_len, knots_len_remaining,
+ SQUARE(error_threshold), dims);
+
+#ifdef USE_CORNER_DETECT
+ if (use_corner) {
+ for (uint i = 0; i < knots_len; i++) {
+ assert(knots[i].heap_node == NULL);
+ }
+
+ knots_len_remaining = curve_incremental_simplify_corners(
+ &pd, knots, knots_len, knots_len_remaining,
+ SQUARE(error_threshold), SQUARE(error_threshold * 3),
+ corner_angle,
+ dims,
+ r_corner_index_len);
+ }
+#endif /* USE_CORNER_DETECT */
+
+#ifdef USE_KNOT_REFIT
+ knots_len_remaining = curve_incremental_simplify_refit(
+ &pd, knots, knots_len, knots_len_remaining,
+ SQUARE(error_threshold),
+ dims);
+#endif /* USE_KNOT_REFIT */
+
+
+#ifdef USE_CORNER_DETECT
+ if (use_corner) {
+ if (is_cyclic == false) {
+ *r_corner_index_len += 2;
+ }
+
+ uint *corner_index_array = malloc(sizeof(uint) * (*r_corner_index_len));
+ uint k_index = 0, c_index = 0;
+ uint i = 0;
+
+ if (is_cyclic == false) {
+ corner_index_array[c_index++] = k_index;
+ k_index++;
+ i++;
+ }
+
+ for (; i < knots_len; i++) {
+ if (knots[i].is_removed == false) {
+ if (knots[i].is_corner == true) {
+ corner_index_array[c_index++] = k_index;
+ }
+ k_index++;
+ }
+ }
+
+ if (is_cyclic == false) {
+ corner_index_array[c_index++] = k_index;
+ k_index++;
+ }
+
+ assert(c_index == *r_corner_index_len);
+ *r_corner_index_array = corner_index_array;
+ }
+#endif /* USE_CORNER_DETECT */
+
+#ifdef USE_LENGTH_CACHE
+ free(points_length_cache);
+#endif
+
+ uint *cubic_orig_index = NULL;
+
+ if (r_cubic_orig_index) {
+ cubic_orig_index = malloc(sizeof(uint) * knots_len_remaining);
+ }
+
+ struct Knot *knots_first = NULL;
+ {
+ struct Knot *k;
+ for (uint i = 0; i < knots_len; i++) {
+ if (knots[i].is_removed == false) {
+ knots_first = &knots[i];
+ break;
+ }
+ }
+
+ if (cubic_orig_index) {
+ k = knots_first;
+ for (uint i = 0; i < knots_len_remaining; i++, k = k->next) {
+ cubic_orig_index[i] = k->index;
+ }
+ }
+ }
+
+ /* Correct unused handle endpoints - not essential, but nice behavior */
+ if (is_cyclic == false) {
+ struct Knot *knots_last = knots_first;
+ while (knots_last->next) {
+ knots_last = knots_last->next;
+ }
+ knots_first->handles[0] = -knots_first->handles[1];
+ knots_last->handles[1] = -knots_last->handles[0];
+ }
+
+ /* 3x for one knot and two handles */
+ double *cubic_array = malloc(sizeof(double) * knots_len_remaining * 3 * dims);
+
+ {
+ double *c_step = cubic_array;
+ struct Knot *k = knots_first;
+ for (uint i = 0; i < knots_len_remaining; i++, k = k->next) {
+ const double *p = &points[k->index * dims];
+
+ madd_vn_vnvn_fl(c_step, p, k->tan[0], k->handles[0], dims);
+ c_step += dims;
+ copy_vnvn(c_step, p, dims);
+ c_step += dims;
+ madd_vn_vnvn_fl(c_step, p, k->tan[1], k->handles[1], dims);
+ c_step += dims;
+ }
+ assert(c_step == &cubic_array[knots_len_remaining * 3 * dims]);
+ }
+
+ if (points_alloc) {
+ free(points_alloc);
+ points_alloc = NULL;
+ }
+
+ free(knots);
+ free(tangents);
+
+ if (r_cubic_orig_index) {
+ *r_cubic_orig_index = cubic_orig_index;
+ }
+
+ *r_cubic_array = cubic_array;
+ *r_cubic_array_len = knots_len_remaining;
+
+ return 0;
+}
+
+
+int curve_fit_cubic_to_points_refit_fl(
+ const float *points,
+ const unsigned int points_len,
+ const unsigned int dims,
+ const float error_threshold,
+ const unsigned int calc_flag,
+ const unsigned int *corners,
+ unsigned int corners_len,
+ const float corner_angle,
+
+ float **r_cubic_array, unsigned int *r_cubic_array_len,
+ unsigned int **r_cubic_orig_index,
+ unsigned int **r_corner_index_array, unsigned int *r_corner_index_len)
+{
+ const uint points_flat_len = points_len * dims;
+ double *points_db = malloc(sizeof(double) * points_flat_len);
+
+ copy_vndb_vnfl(points_db, points, points_flat_len);
+
+ double *cubic_array_db = NULL;
+ float *cubic_array_fl = NULL;
+ uint cubic_array_len = 0;
+
+ int result = curve_fit_cubic_to_points_refit_db(
+ points_db, points_len, dims, error_threshold, calc_flag, corners, corners_len,
+ corner_angle,
+ &cubic_array_db, &cubic_array_len,
+ r_cubic_orig_index,
+ r_corner_index_array, r_corner_index_len);
+ free(points_db);
+
+ if (!result) {
+ uint cubic_array_flat_len = cubic_array_len * 3 * dims;
+ cubic_array_fl = malloc(sizeof(float) * cubic_array_flat_len);
+ for (uint i = 0; i < cubic_array_flat_len; i++) {
+ cubic_array_fl[i] = (float)cubic_array_db[i];
+ }
+ free(cubic_array_db);
+ }
+
+ *r_cubic_array = cubic_array_fl;
+ *r_cubic_array_len = cubic_array_len;
+
+ return result;
+}
+
diff --git a/extern/curve_fit_nd/intern/curve_fit_inline.h b/extern/curve_fit_nd/intern/curve_fit_inline.h
index c77e5c6e062..f9eaa4c647c 100644
--- a/extern/curve_fit_nd/intern/curve_fit_inline.h
+++ b/extern/curve_fit_nd/intern/curve_fit_inline.h
@@ -290,14 +290,12 @@ MINLINE bool equals_vnvn(
return true;
}
-#if 0
MINLINE void project_vn_vnvn(
double v_out[], const double p[], const double v_proj[], const uint dims)
{
const double mul = dot_vnvn(p, v_proj, dims) / dot_vnvn(v_proj, v_proj, dims);
mul_vnvn_fl(v_out, v_proj, mul, dims);
}
-#endif
MINLINE void project_vn_vnvn_normalized(
double v_out[], const double p[], const double v_proj[], const uint dims)
diff --git a/extern/curve_fit_nd/intern/generic_alloc_impl.h b/extern/curve_fit_nd/intern/generic_alloc_impl.h
new file mode 100644
index 00000000000..687c154f14a
--- /dev/null
+++ b/extern/curve_fit_nd/intern/generic_alloc_impl.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2016, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file generic_alloc_impl.c
+ * \ingroup curve_fit
+ *
+ * Simple Memory Chunking Allocator
+ * ================================
+ *
+ * Defines need to be set:
+ * - #TPOOL_IMPL_PREFIX: Prefix to use for the API.
+ * - #TPOOL_ALLOC_TYPE: Struct type this pool handles.
+ * - #TPOOL_STRUCT: Name for pool struct name.
+ * - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined.
+ *
+ * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``.
+ *
+ * Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function.
+ *
+ * - *_pool_create()
+ * - *_pool_destroy()
+ * - *_pool_clear()
+ *
+ * - *_pool_elem_alloc()
+ * - *_pool_elem_calloc()
+ * - *_pool_elem_free()
+ */
+
+/* check we're not building directly */
+#if !defined(TPOOL_IMPL_PREFIX) || \
+ !defined(TPOOL_ALLOC_TYPE) || \
+ !defined(TPOOL_STRUCT)
+# error "This file can't be compiled directly, include in another source file"
+#endif
+
+#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2
+#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
+#define _TPOOL_PREFIX(id) _CONCAT(TPOOL_IMPL_PREFIX, _##id)
+
+/* local identifiers */
+#define pool_create _TPOOL_PREFIX(pool_create)
+#define pool_destroy _TPOOL_PREFIX(pool_destroy)
+#define pool_clear _TPOOL_PREFIX(pool_clear)
+
+#define pool_elem_alloc _TPOOL_PREFIX(pool_elem_alloc)
+#define pool_elem_calloc _TPOOL_PREFIX(pool_elem_calloc)
+#define pool_elem_free _TPOOL_PREFIX(pool_elem_free)
+
+/* private identifiers (only for this file, undefine after) */
+#define pool_alloc_chunk _TPOOL_PREFIX(pool_alloc_chunk)
+#define TPoolChunk _TPOOL_PREFIX(TPoolChunk)
+#define TPoolChunkElemFree _TPOOL_PREFIX(TPoolChunkElemFree)
+
+#ifndef TPOOL_CHUNK_SIZE
+#define TPOOL_CHUNK_SIZE (1 << 16) /* 64kb */
+#define _TPOOL_CHUNK_SIZE_UNDEF
+#endif
+
+#ifndef UNLIKELY
+# ifdef __GNUC__
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+# else
+# define UNLIKELY(x) (x)
+# endif
+#endif
+
+#ifdef __GNUC__
+# define MAYBE_UNUSED __attribute__((unused))
+#else
+# define MAYBE_UNUSED
+#endif
+
+
+struct TPoolChunk {
+ struct TPoolChunk *prev;
+ unsigned int size;
+ unsigned int bufsize;
+ TPOOL_ALLOC_TYPE buf[0];
+};
+
+struct TPoolChunkElemFree {
+ struct TPoolChunkElemFree *next;
+};
+
+struct TPOOL_STRUCT {
+ /* Always keep at least one chunk (never NULL) */
+ struct TPoolChunk *chunk;
+ /* when NULL, allocate a new chunk */
+ struct TPoolChunkElemFree *free;
+};
+
+/**
+ * Number of elems to include per #TPoolChunk when no reserved size is passed,
+ * or we allocate past the reserved number.
+ *
+ * \note Optimize number for 64kb allocs.
+ */
+#define _TPOOL_CHUNK_DEFAULT_NUM \
+ (((1 << 16) - sizeof(struct TPoolChunk)) / sizeof(TPOOL_ALLOC_TYPE))
+
+
+/** \name Internal Memory Management
+ * \{ */
+
+static struct TPoolChunk *pool_alloc_chunk(
+ unsigned int tot_elems, struct TPoolChunk *chunk_prev)
+{
+ struct TPoolChunk *chunk = malloc(
+ sizeof(struct TPoolChunk) + (sizeof(TPOOL_ALLOC_TYPE) * tot_elems));
+ chunk->prev = chunk_prev;
+ chunk->bufsize = tot_elems;
+ chunk->size = 0;
+ return chunk;
+}
+
+static TPOOL_ALLOC_TYPE *pool_elem_alloc(struct TPOOL_STRUCT *pool)
+{
+ TPOOL_ALLOC_TYPE *elem;
+
+ if (pool->free) {
+ elem = (TPOOL_ALLOC_TYPE *)pool->free;
+ pool->free = pool->free->next;
+ }
+ else {
+ struct TPoolChunk *chunk = pool->chunk;
+ if (UNLIKELY(chunk->size == chunk->bufsize)) {
+ chunk = pool->chunk = pool_alloc_chunk(_TPOOL_CHUNK_DEFAULT_NUM, chunk);
+ }
+ elem = &chunk->buf[chunk->size++];
+ }
+
+ return elem;
+}
+
+MAYBE_UNUSED
+static TPOOL_ALLOC_TYPE *pool_elem_calloc(struct TPOOL_STRUCT *pool)
+{
+ TPOOL_ALLOC_TYPE *elem = pool_elem_alloc(pool);
+ memset(elem, 0, sizeof(*elem));
+ return elem;
+}
+
+static void pool_elem_free(struct TPOOL_STRUCT *pool, TPOOL_ALLOC_TYPE *elem)
+{
+ struct TPoolChunkElemFree *elem_free = (struct TPoolChunkElemFree *)elem;
+ elem_free->next = pool->free;
+ pool->free = elem_free;
+}
+
+static void pool_create(struct TPOOL_STRUCT *pool, unsigned int tot_reserve)
+{
+ pool->chunk = pool_alloc_chunk((tot_reserve > 1) ? tot_reserve : _TPOOL_CHUNK_DEFAULT_NUM, NULL);
+ pool->free = NULL;
+}
+
+MAYBE_UNUSED
+static void pool_clear(struct TPOOL_STRUCT *pool)
+{
+ /* Remove all except the last chunk */
+ while (pool->chunk->prev) {
+ struct TPoolChunk *chunk_prev = pool->chunk->prev;
+ free(pool->chunk);
+ pool->chunk = chunk_prev;
+ }
+ pool->chunk->size = 0;
+ pool->free = NULL;
+}
+
+static void pool_destroy(struct TPOOL_STRUCT *pool)
+{
+ struct TPoolChunk *chunk = pool->chunk;
+ do {
+ struct TPoolChunk *chunk_prev;
+ chunk_prev = chunk->prev;
+ free(chunk);
+ chunk = chunk_prev;
+ } while (chunk);
+
+ pool->chunk = NULL;
+ pool->free = NULL;
+}
+
+/** \} */
+
+#undef _TPOOL_CHUNK_DEFAULT_NUM
+#undef _CONCAT_AUX
+#undef _CONCAT
+#undef _TPOOL_PREFIX
+
+#undef TPoolChunk
+#undef TPoolChunkElemFree
+
+#ifdef _TPOOL_CHUNK_SIZE_UNDEF
+# undef TPOOL_CHUNK_SIZE
+# undef _TPOOL_CHUNK_SIZE_UNDEF
+#endif
diff --git a/extern/curve_fit_nd/intern/generic_heap.c b/extern/curve_fit_nd/intern/generic_heap.c
new file mode 100644
index 00000000000..1e2efa5b43d
--- /dev/null
+++ b/extern/curve_fit_nd/intern/generic_heap.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2016, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** \file generic_heap.c
+ * \ingroup curve_fit
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "generic_heap.h"
+
+/* swap with a temp value */
+#define SWAP_TVAL(tval, a, b) { \
+ (tval) = (a); \
+ (a) = (b); \
+ (b) = (tval); \
+} (void)0
+
+#ifdef __GNUC__
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+# define UNLIKELY(x) (x)
+#endif
+
+
+/***/
+
+struct HeapNode {
+ void *ptr;
+ double value;
+ unsigned int index;
+};
+
+/* heap_* pool allocator */
+#define TPOOL_IMPL_PREFIX heap
+#define TPOOL_ALLOC_TYPE HeapNode
+#define TPOOL_STRUCT HeapMemPool
+#include "generic_alloc_impl.h"
+#undef TPOOL_IMPL_PREFIX
+#undef TPOOL_ALLOC_TYPE
+#undef TPOOL_STRUCT
+
+struct Heap {
+ unsigned int size;
+ unsigned int bufsize;
+ HeapNode **tree;
+
+ struct HeapMemPool pool;
+};
+
+/** \name Internal Functions
+ * \{ */
+
+#define HEAP_PARENT(i) (((i) - 1) >> 1)
+#define HEAP_LEFT(i) (((i) << 1) + 1)
+#define HEAP_RIGHT(i) (((i) << 1) + 2)
+#define HEAP_COMPARE(a, b) ((a)->value < (b)->value)
+
+#if 0 /* UNUSED */
+#define HEAP_EQUALS(a, b) ((a)->value == (b)->value)
+#endif
+
+static void heap_swap(Heap *heap, const unsigned int i, const unsigned int j)
+{
+
+#if 0
+ SWAP(unsigned int, heap->tree[i]->index, heap->tree[j]->index);
+ SWAP(HeapNode *, heap->tree[i], heap->tree[j]);
+#else
+ HeapNode **tree = heap->tree;
+ union {
+ unsigned int index;
+ HeapNode *node;
+ } tmp;
+ SWAP_TVAL(tmp.index, tree[i]->index, tree[j]->index);
+ SWAP_TVAL(tmp.node, tree[i], tree[j]);
+#endif
+}
+
+static void heap_down(Heap *heap, unsigned int i)
+{
+ /* size won't change in the loop */
+ const unsigned int size = heap->size;
+
+ while (1) {
+ const unsigned int l = HEAP_LEFT(i);
+ const unsigned int r = HEAP_RIGHT(i);
+ unsigned int smallest;
+
+ smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i;
+
+ if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) {
+ smallest = r;
+ }
+
+ if (smallest == i) {
+ break;
+ }
+
+ heap_swap(heap, i, smallest);
+ i = smallest;
+ }
+}
+
+static void heap_up(Heap *heap, unsigned int i)
+{
+ while (i > 0) {
+ const unsigned int p = HEAP_PARENT(i);
+
+ if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) {
+ break;
+ }
+ heap_swap(heap, p, i);
+ i = p;
+ }
+}
+
+/** \} */
+
+
+/** \name Public Heap API
+ * \{ */
+
+/* use when the size of the heap is known in advance */
+Heap *HEAP_new(unsigned int tot_reserve)
+{
+ Heap *heap = malloc(sizeof(Heap));
+ /* ensure we have at least one so we can keep doubling it */
+ heap->size = 0;
+ heap->bufsize = tot_reserve ? tot_reserve : 1;
+ heap->tree = malloc(heap->bufsize * sizeof(HeapNode *));
+
+ heap_pool_create(&heap->pool, tot_reserve);
+
+ return heap;
+}
+
+void HEAP_free(Heap *heap, HeapFreeFP ptrfreefp)
+{
+ if (ptrfreefp) {
+ unsigned int i;
+
+ for (i = 0; i < heap->size; i++) {
+ ptrfreefp(heap->tree[i]->ptr);
+ }
+ }
+
+ heap_pool_destroy(&heap->pool);
+
+ free(heap->tree);
+ free(heap);
+}
+
+void HEAP_clear(Heap *heap, HeapFreeFP ptrfreefp)
+{
+ if (ptrfreefp) {
+ unsigned int i;
+
+ for (i = 0; i < heap->size; i++) {
+ ptrfreefp(heap->tree[i]->ptr);
+ }
+ }
+ heap->size = 0;
+
+ heap_pool_clear(&heap->pool);
+}
+
+HeapNode *HEAP_insert(Heap *heap, double value, void *ptr)
+{
+ HeapNode *node;
+
+ if (UNLIKELY(heap->size >= heap->bufsize)) {
+ heap->bufsize *= 2;
+ heap->tree = realloc(heap->tree, heap->bufsize * sizeof(*heap->tree));
+ }
+
+ node = heap_pool_elem_alloc(&heap->pool);
+
+ node->ptr = ptr;
+ node->value = value;
+ node->index = heap->size;
+
+ heap->tree[node->index] = node;
+
+ heap->size++;
+
+ heap_up(heap, node->index);
+
+ return node;
+}
+
+bool HEAP_is_empty(Heap *heap)
+{
+ return (heap->size == 0);
+}
+
+unsigned int HEAP_size(Heap *heap)
+{
+ return heap->size;
+}
+
+HeapNode *HEAP_top(Heap *heap)
+{
+ return heap->tree[0];
+}
+
+double HEAP_top_value(Heap *heap)
+{
+ return heap->tree[0]->value;
+}
+
+void *HEAP_popmin(Heap *heap)
+{
+ void *ptr = heap->tree[0]->ptr;
+
+ assert(heap->size != 0);
+
+ heap_pool_elem_free(&heap->pool, heap->tree[0]);
+
+ if (--heap->size) {
+ heap_swap(heap, 0, heap->size);
+ heap_down(heap, 0);
+ }
+
+ return ptr;
+}
+
+void HEAP_remove(Heap *heap, HeapNode *node)
+{
+ unsigned int i = node->index;
+
+ assert(heap->size != 0);
+
+ while (i > 0) {
+ unsigned int p = HEAP_PARENT(i);
+
+ heap_swap(heap, p, i);
+ i = p;
+ }
+
+ HEAP_popmin(heap);
+}
+
+double HEAP_node_value(HeapNode *node)
+{
+ return node->value;
+}
+
+void *HEAP_node_ptr(HeapNode *node)
+{
+ return node->ptr;
+}
diff --git a/extern/curve_fit_nd/intern/generic_heap.h b/extern/curve_fit_nd/intern/generic_heap.h
new file mode 100644
index 00000000000..e39344cf076
--- /dev/null
+++ b/extern/curve_fit_nd/intern/generic_heap.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __GENERIC_HEAP_H__
+#define __GENERIC_HEAP_H__
+
+/** \file generic_heap.h
+ * \ingroup curve_fit
+ */
+
+struct Heap;
+struct HeapNode;
+typedef struct Heap Heap;
+typedef struct HeapNode HeapNode;
+
+typedef void (*HeapFreeFP)(void *ptr);
+
+Heap *HEAP_new(unsigned int tot_reserve);
+bool HEAP_is_empty(Heap *heap);
+void HEAP_free(Heap *heap, HeapFreeFP ptrfreefp);
+void *HEAP_node_ptr(HeapNode *node);
+void HEAP_remove(Heap *heap, HeapNode *node);
+HeapNode *HEAP_insert(Heap *heap, double value, void *ptr);
+void *HEAP_popmin(Heap *heap);
+void HEAP_clear(Heap *heap, HeapFreeFP ptrfreefp);
+unsigned int HEAP_size(Heap *heap);
+HeapNode *HEAP_top(Heap *heap);
+double HEAP_top_value(Heap *heap);
+double HEAP_node_value(HeapNode *node);
+
+#endif /* __GENERIC_HEAP_IMPL_H__ */
diff --git a/intern/atomic/intern/atomic_ops_utils.h b/intern/atomic/intern/atomic_ops_utils.h
index fcbb2346243..bfec9918c16 100644
--- a/intern/atomic/intern/atomic_ops_utils.h
+++ b/intern/atomic/intern/atomic_ops_utils.h
@@ -81,7 +81,9 @@
# endif
#endif
-#ifdef UINTPTR_MAX
+#if defined(__SIZEOF_POINTER__)
+# define LG_SIZEOF_PTR __SIZEOF_POINTER__
+#elif defined(UINTPTR_MAX)
# if (UINTPTR_MAX == 0xFFFFFFFF)
# define LG_SIZEOF_PTR 4
# elif (UINTPTR_MAX == 0xFFFFFFFFFFFFFFFF)
diff --git a/intern/audaspace/Python/AUD_PyAPI.cpp b/intern/audaspace/Python/AUD_PyAPI.cpp
index 300fd55e23b..de5c0a2f463 100644
--- a/intern/audaspace/Python/AUD_PyAPI.cpp
+++ b/intern/audaspace/Python/AUD_PyAPI.cpp
@@ -861,7 +861,7 @@ Factory_filter(Factory* self, PyObject *args)
py_a_len= py_a ? PySequence_Size(py_a) : 0;
py_b_len= PySequence_Size(py_b);
- if(!py_b_len || ((py_a != NULL) && !py_b_len))
+ if(!py_b_len || ((py_a != NULL) && !py_a_len))
{
PyErr_SetString(PyExc_ValueError, "The sequence has to contain at least one value!");
return NULL;
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 140862721a8..0b3dd552f62 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -503,6 +503,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
description="Use BVH spatial splits: longer builder time, faster render",
default=False,
)
+ cls.debug_use_hair_bvh = BoolProperty(
+ name="Use Hair BVH",
+ description="Use special type BVH optimized for hair (uses more ram but renders faster)",
+ default=True,
+ )
cls.tile_order = EnumProperty(
name="Tile Order",
description="Tile order for rendering",
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 120199479fe..6656beb4478 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -401,6 +401,7 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
col.label(text="Acceleration structure:")
col.prop(cscene, "debug_use_spatial_splits")
+ col.prop(cscene, "debug_use_hair_bvh")
class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
@@ -458,7 +459,9 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel):
col.prop(rl, "use_pass_z")
col.prop(rl, "use_pass_mist")
col.prop(rl, "use_pass_normal")
- col.prop(rl, "use_pass_vector")
+ row = col.row()
+ row.prop(rl, "use_pass_vector")
+ row.active = not rd.use_motion_blur
col.prop(rl, "use_pass_uv")
col.prop(rl, "use_pass_object_index")
col.prop(rl, "use_pass_material_index")
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index 4bd385c4200..ec11a893b5a 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -680,6 +680,43 @@ static void create_subd_mesh(Scene *scene,
/* Sync */
+static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh)
+{
+ if(scene->need_motion() == Scene::MOTION_NONE)
+ return;
+
+ BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
+
+ if(!b_fluid_domain)
+ return;
+
+ /* If the mesh has modifiers following the fluid domain we can't export motion. */
+ if(b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size())
+ return;
+
+ /* Find or add attribute */
+ float3 *P = &mesh->verts[0];
+ Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if(!attr_mP) {
+ attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+
+ /* Only export previous and next frame, we don't have any in between data. */
+ float motion_times[2] = {-1.0f, 1.0f};
+ for (int step = 0; step < 2; step++) {
+ float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
+ float3 *mP = attr_mP->data_float3() + step*mesh->verts.size();
+
+ BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi;
+ int i = 0;
+
+ for(b_fluid_domain.fluid_mesh_vertices.begin(fvi); fvi != b_fluid_domain.fluid_mesh_vertices.end(); ++fvi, ++i) {
+ mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time;
+ }
+ }
+}
+
Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
bool object_updated,
bool hide_tris)
@@ -821,6 +858,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
mesh->displacement_method = Mesh::DISPLACE_BOTH;
}
+ /* fluid motion */
+ sync_mesh_fluid_motion(b_ob, scene, mesh);
+
/* tag update */
bool rebuild = false;
@@ -910,6 +950,11 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob,
* would need a more extensive check to see which objects are animated */
BL::Mesh b_mesh(PointerRNA_NULL);
+ /* fluid motion is exported immediate with mesh, skip here */
+ BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob);
+ if (b_fluid_domain)
+ return;
+
if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
/* get derived mesh */
b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 80768c096e3..22a0b3988c8 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -253,11 +253,10 @@ static bool object_boundbox_clip(Scene *scene,
boundbox[3 * i + 1],
boundbox[3 * i + 2]);
p = transform_point(&tfm, p);
- p = transform_point(&worldtondc, p);
+ p = transform_perspective(&worldtondc, p);
if(p.z >= -margin) {
all_behind = false;
}
- p /= p.z;
bb_min = min(bb_min, p);
bb_max = max(bb_max, p);
}
@@ -720,12 +719,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render,
<< relative_time << ".";
/* fixed shutter time to get previous and next frame for motion pass */
- float shuttertime;
-
- if(scene->need_motion() == Scene::MOTION_PASS)
- shuttertime = 2.0f;
- else
- shuttertime = scene->camera->shuttertime;
+ float shuttertime = scene->motion_shutter_time();
/* compute frame and subframe time */
float time = frame_center + frame_center_delta + relative_time * shuttertime * 0.5f;
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 33084f1c163..e7e57b2be36 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -492,6 +492,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
SceneParams::BVH_STATIC);
params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
+ params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh");
if(background && params.shadingsystem != SHADINGSYSTEM_OSL)
params.persistent_data = r.use_persistent_data();
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
index d690adb5662..b8b9597914e 100644
--- a/intern/cycles/blender/blender_sync.h
+++ b/intern/cycles/blender/blender_sync.h
@@ -131,7 +131,9 @@ private:
Transform& tfm,
bool *use_portal);
void sync_background_light(bool use_portal);
- void sync_mesh_motion(BL::Object& b_ob, Object *object, float motion_time);
+ void sync_mesh_motion(BL::Object& b_ob,
+ Object *object,
+ float motion_time);
void sync_camera_motion(BL::RenderSettings& b_render,
BL::Object& b_ob,
int width, int height,
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
index 2510cebcdc0..188d23d0c59 100644
--- a/intern/cycles/blender/blender_util.h
+++ b/intern/cycles/blender/blender_util.h
@@ -519,6 +519,23 @@ static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object& b_ob)
return BL::SmokeDomainSettings(PointerRNA_NULL);
}
+static inline BL::DomainFluidSettings object_fluid_domain_find(BL::Object b_ob)
+{
+ BL::Object::modifiers_iterator b_mod;
+
+ for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
+ if(b_mod->is_a(&RNA_FluidSimulationModifier)) {
+ BL::FluidSimulationModifier b_fmd(*b_mod);
+ BL::FluidSettings fss = b_fmd.settings();
+
+ if(fss.type() == BL::FluidSettings::type_DOMAIN)
+ return (BL::DomainFluidSettings)b_fmd.settings();
+ }
+ }
+
+ return BL::DomainFluidSettings(PointerRNA_NULL);
+}
+
/* ID Map
*
* Utility class to keep in sync with blender data.
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
index e92526ac1c4..1bb3e95c810 100644
--- a/intern/cycles/bvh/bvh.cpp
+++ b/intern/cycles/bvh/bvh.cpp
@@ -463,8 +463,7 @@ void RegularBVH::pack_aligned_inner(const BVHStackEntry& e,
pack_aligned_node(e.idx,
e0.node->m_bounds, e1.node->m_bounds,
e0.encodeIdx(), e1.encodeIdx(),
- e0.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED,
- e1.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED);
+ e0.node->m_visibility, e1.node->m_visibility);
}
void RegularBVH::pack_aligned_node(int idx,
@@ -475,7 +474,8 @@ void RegularBVH::pack_aligned_node(int idx,
{
int4 data[BVH_NODE_SIZE] =
{
- make_int4(visibility0, visibility1, c0, c1),
+ make_int4(visibility0 & ~PATH_RAY_NODE_UNALIGNED,
+ visibility1 & ~PATH_RAY_NODE_UNALIGNED, c0, c1),
make_int4(__float_as_int(b0.min.x), __float_as_int(b1.min.x), __float_as_int(b0.max.x), __float_as_int(b1.max.x)),
make_int4(__float_as_int(b0.min.y), __float_as_int(b1.min.y), __float_as_int(b0.max.y), __float_as_int(b1.max.y)),
make_int4(__float_as_int(b0.min.z), __float_as_int(b1.min.z), __float_as_int(b0.max.z), __float_as_int(b1.max.z)),
@@ -688,9 +688,7 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
leaf_data[0].y = __int_as_float(c1);
leaf_data[0].z = __uint_as_float(visibility);
leaf_data[0].w = __uint_as_float(data[0].w);
- memcpy(&pack.leaf_nodes[idx * BVH_NODE_LEAF_SIZE],
- leaf_data,
- sizeof(float4)*BVH_NODE_LEAF_SIZE);
+ memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_NODE_LEAF_SIZE);
}
else {
int4 *data = &pack.nodes[idx];
diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp
index afe21c49730..50490f3a20e 100644
--- a/intern/cycles/device/device_opencl.cpp
+++ b/intern/cycles/device/device_opencl.cpp
@@ -795,7 +795,7 @@ public:
bool load_binary(const string& /*kernel_path*/,
const string& clbin,
- string custom_kernel_build_options,
+ const string& custom_kernel_build_options,
cl_program *program,
const string *debug_src = NULL)
{
@@ -848,7 +848,7 @@ public:
}
bool build_kernel(cl_program *kernel_program,
- string custom_kernel_build_options,
+ const string& custom_kernel_build_options,
const string *debug_src = NULL)
{
string build_options;
@@ -881,30 +881,39 @@ public:
return true;
}
- bool compile_kernel(const string& kernel_path,
- string source,
- string custom_kernel_build_options,
+ bool compile_kernel(const string& kernel_name,
+ const string& kernel_path,
+ const string& source,
+ const string& custom_kernel_build_options,
cl_program *kernel_program,
const string *debug_src = NULL)
{
- /* we compile kernels consisting of many files. unfortunately opencl
+ /* We compile kernels consisting of many files. unfortunately OpenCL
* kernel caches do not seem to recognize changes in included files.
- * so we force recompile on changes by adding the md5 hash of all files */
- source = path_source_replace_includes(source, kernel_path);
+ * so we force recompile on changes by adding the md5 hash of all files.
+ */
+ string inlined_source = path_source_replace_includes(source,
+ kernel_path);
- if(debug_src)
- path_write_text(*debug_src, source);
+ if(debug_src) {
+ path_write_text(*debug_src, inlined_source);
+ }
- size_t source_len = source.size();
- const char *source_str = source.c_str();
+ size_t source_len = inlined_source.size();
+ const char *source_str = inlined_source.c_str();
- *kernel_program = clCreateProgramWithSource(cxContext, 1, &source_str, &source_len, &ciErr);
+ *kernel_program = clCreateProgramWithSource(cxContext,
+ 1,
+ &source_str,
+ &source_len,
+ &ciErr);
- if(opencl_error(ciErr))
+ if(opencl_error(ciErr)) {
return false;
+ }
double starttime = time_dt();
- printf("Compiling OpenCL kernel ...\n");
+ printf("Compiling %s OpenCL kernel ...\n", kernel_name.c_str());
/* TODO(sergey): Report which kernel is being compiled
* as well (megakernel or which of split kernels etc..).
*/
@@ -1004,7 +1013,8 @@ public:
string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " + kernel_md5 + "\n";
/* If does not exist or loading binary failed, compile kernel. */
- if(!compile_kernel(kernel_path,
+ if(!compile_kernel("base_kernel",
+ kernel_path,
init_kernel_source,
build_flags,
&cpProgram,
@@ -1694,7 +1704,8 @@ public:
string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " +
kernel_md5 + "\n";
/* If does not exist or loading binary failed, compile kernel. */
- if(!compile_kernel(kernel_path,
+ if(!compile_kernel("mega_kernel",
+ kernel_path,
init_kernel_source,
custom_kernel_build_options,
&path_trace_program,
@@ -2078,30 +2089,33 @@ public:
/* TODO(sergey): Seems really close to load_kernel(),
* could it be de-duplicated?
*/
- bool load_split_kernel(string kernel_path,
- string kernel_init_source,
- string clbin,
- string custom_kernel_build_options,
+ bool load_split_kernel(const string& kernel_name,
+ const string& kernel_path,
+ const string& kernel_init_source,
+ const string& clbin,
+ const string& custom_kernel_build_options,
cl_program *program,
const string *debug_src = NULL)
{
- if(!opencl_version_check())
+ if(!opencl_version_check()) {
return false;
+ }
- clbin = path_user_get(path_join("cache", clbin));
+ string cache_clbin = path_user_get(path_join("cache", clbin));
/* If exists already, try use it. */
- if(path_exists(clbin) && load_binary(kernel_path,
- clbin,
- custom_kernel_build_options,
- program,
- debug_src))
+ if(path_exists(cache_clbin) && load_binary(kernel_path,
+ cache_clbin,
+ custom_kernel_build_options,
+ program,
+ debug_src))
{
/* Kernel loaded from binary. */
}
else {
/* If does not exist or loading binary failed, compile kernel. */
- if(!compile_kernel(kernel_path,
+ if(!compile_kernel(kernel_name,
+ kernel_path,
kernel_init_source,
custom_kernel_build_options,
program,
@@ -2110,7 +2124,7 @@ public:
return false;
}
/* Save binary for reuse. */
- if(!save_binary(program, clbin)) {
+ if(!save_binary(program, cache_clbin)) {
return false;
}
}
@@ -2208,7 +2222,10 @@ public:
clsrc = path_user_get(path_join("cache", clsrc)); \
debug_src = &clsrc; \
} \
- if(!load_split_kernel(kernel_path, kernel_init_source, clbin, \
+ if(!load_split_kernel(#name, \
+ kernel_path, \
+ kernel_init_source, \
+ clbin, \
build_options, \
&GLUE(name, _program), \
debug_src)) \
diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h
index 1869457f0c3..b27afaa9869 100644
--- a/intern/cycles/kernel/bvh/bvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h
@@ -283,7 +283,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
return true;
}
/* if maximum number of hits reached, block all light */
- else if(*num_hits == max_hits) {
+ else if(*num_hits >= max_hits) {
return true;
}
diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h
index b5405e8e57b..d7f6bf86c71 100644
--- a/intern/cycles/kernel/bvh/bvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/bvh_volume_all.h
@@ -206,7 +206,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
#endif
- if(num_hits == max_hits) {
+ if(num_hits >= max_hits) {
#if BVH_FEATURE(BVH_INSTANCING)
# if BVH_FEATURE(BVH_MOTION)
float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
@@ -252,7 +252,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
# if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
# endif
- if(num_hits == max_hits) {
+ if(num_hits >= max_hits) {
# if BVH_FEATURE(BVH_INSTANCING)
# if BVH_FEATURE(BVH_MOTION)
float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
index 34753ff067d..eb98eaf7455 100644
--- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h
+++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h
@@ -366,7 +366,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
return true;
}
/* if maximum number of hits reached, block all light */
- else if(*num_hits == max_hits) {
+ else if(*num_hits >= max_hits) {
return true;
}
diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h
index a877e5bb341..90cad9d91c0 100644
--- a/intern/cycles/kernel/bvh/qbvh_volume_all.h
+++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h
@@ -273,7 +273,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
#if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
#endif
- if(num_hits == max_hits) {
+ if(num_hits >= max_hits) {
#if BVH_FEATURE(BVH_INSTANCING)
# if BVH_FEATURE(BVH_MOTION)
float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
@@ -312,7 +312,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
# if BVH_FEATURE(BVH_INSTANCING)
num_hits_in_instance++;
# endif
- if(num_hits == max_hits) {
+ if(num_hits >= max_hits) {
# if BVH_FEATURE(BVH_INSTANCING)
# if BVH_FEATURE(BVH_MOTION)
float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir));
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index aa21633070a..7bf7c2806d4 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -615,6 +615,36 @@ ccl_device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness
sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */
}
+ccl_device_inline float bsdf_beckmann_G1(float alpha, float cos_n)
+{
+ cos_n *= cos_n;
+ float invA = alpha * safe_sqrtf((1.0f - cos_n) / cos_n);
+ if(invA < 0.625f) {
+ return 1.0f;
+ }
+
+ float a = 1.0f / invA;
+ return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f);
+}
+
+ccl_device_inline float bsdf_beckmann_aniso_G1(float alpha_x, float alpha_y, float cos_n, float cos_phi, float sin_phi)
+{
+ cos_n *= cos_n;
+ sin_phi *= sin_phi;
+ cos_phi *= cos_phi;
+ alpha_x *= alpha_x;
+ alpha_y *= alpha_y;
+
+ float alphaO2 = (cos_phi*alpha_x + sin_phi*alpha_y) / (cos_phi + sin_phi);
+ float invA = safe_sqrtf(alphaO2 * (1 - cos_n) / cos_n);
+ if(invA < 0.625f) {
+ return 1.0f;
+ }
+
+ float a = 1.0f / invA;
+ return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f);
+}
+
ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
{
float alpha_x = sc->data0;
@@ -646,10 +676,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
/* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */
- float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ G1o = bsdf_beckmann_G1(alpha_x, cosNO);
+ G1i = bsdf_beckmann_G1(alpha_x, cosNI);
}
else {
/* anisotropic */
@@ -668,24 +696,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc,
D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4);
/* G1(i,m) and G1(o,m) */
- float tanThetaO2 = (1 - cosNO * cosNO) / (cosNO * cosNO);
- float cosPhiO = dot(I, X);
- float sinPhiO = dot(I, Y);
-
- float alphaO2 = (cosPhiO*cosPhiO)*(alpha_x*alpha_x) + (sinPhiO*sinPhiO)*(alpha_y*alpha_y);
- alphaO2 /= cosPhiO*cosPhiO + sinPhiO*sinPhiO;
-
- float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI);
- float cosPhiI = dot(omega_in, X);
- float sinPhiI = dot(omega_in, Y);
-
- float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y);
- alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI;
-
- float ao = 1 / (safe_sqrtf(alphaO2 * tanThetaO2));
- float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2));
- G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ G1o = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNO, dot(I, X), dot(I, Y));
+ G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNI, dot(omega_in, X), dot(omega_in, Y));
}
float G = G1o * G1i;
@@ -740,10 +752,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc
float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
/* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */
- float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
- float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G1o = bsdf_beckmann_G1(alpha_x, cosNO);
+ float G1i = bsdf_beckmann_G1(alpha_x, cosNI);
float G = G1o * G1i;
/* probability */
@@ -820,8 +830,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
float cosNI = dot(N, *omega_in);
/* eq. 26, 27: now calculate G1(i,m) */
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ G1i = bsdf_beckmann_G1(alpha_x, cosNI);
}
else {
/* anisotropic distribution */
@@ -836,16 +845,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4);
/* G1(i,m) */
- float cosNI = dot(N, *omega_in);
- float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI);
- float cosPhiI = dot(*omega_in, X);
- float sinPhiI = dot(*omega_in, Y);
-
- float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y);
- alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI;
-
- float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2));
- G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, dot(*omega_in, N), dot(*omega_in, X), dot(*omega_in, Y));
}
float G = G1o * G1i;
@@ -906,8 +906,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl
float cosNI = dot(N, *omega_in);
/* eq. 26, 27: now calculate G1(i,m) */
- float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
- float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G1i = bsdf_beckmann_G1(alpha_x, cosNI);
float G = G1o * G1i;
/* eq. 21 */
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
index 6060d7d8ccb..acb50ce6faa 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -42,7 +42,7 @@ ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha)
/* Sample slope distribution (based on page 14 of the supplemental implementation). */
ccl_device_inline float2 mf_sampleP22_11(const float cosI, const float2 randU)
{
- if(cosI > 0.9999f) {
+ if(cosI > 0.9999f || cosI < 1e-6f) {
const float r = sqrtf(randU.x / (1.0f - randU.x));
const float phi = M_2PI_F * randU.y;
return make_float2(r*cosf(phi), r*sinf(phi));
@@ -117,7 +117,7 @@ ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda
if(dotW_WH < 0.0f)
return make_float3(0.0f, 0.0f, 0.0f);
- float phase = max(0.0f, dotW_WH) * 0.25f / (pArea * dotW_WH);
+ float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f);
if(alpha.x == alpha.y)
phase *= D_ggx(wh, alpha.x);
else
@@ -200,9 +200,9 @@ ccl_device_inline float mf_lambda(const float3 w, const float2 alpha)
if(w.z > 0.9999f)
return 0.0f;
else if(w.z < -0.9999f)
- return -1.0f;
+ return -0.9999f;
- const float inv_wz2 = 1.0f / (w.z*w.z);
+ const float inv_wz2 = 1.0f / max(w.z*w.z, 1e-7f);
const float2 wa = make_float2(w.x, w.y)*alpha;
float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2);
if(w.z <= 0.0f)
@@ -271,7 +271,10 @@ ccl_device_inline float mf_ggx_albedo(float r)
ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha)
{
- return 0.25f * D_ggx(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, make_float2(alpha, alpha))) * wi.z) + (1.0f - mf_ggx_albedo(alpha)) * wo.z;
+ float D = D_ggx(normalize(wi+wo), alpha);
+ float lambda = mf_lambda(wi, make_float2(alpha, alpha));
+ float albedo = mf_ggx_albedo(alpha);
+ return 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f) + (1.0f - albedo) * wo.z;
}
ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha)
@@ -348,11 +351,7 @@ ccl_device int bsdf_microfacet_multi_ggx_common_setup(ShaderClosure *sc)
ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(ShaderClosure *sc)
{
-#ifdef __KERNEL_OPENCL__
- if(all(sc->T == 0.0f))
-#else
- if(sc->T == make_float3(0.0f, 0.0f, 0.0f))
-#endif
+ if(is_zero(sc->T))
sc->T = make_float3(1.0f, 0.0f, 0.0f);
return bsdf_microfacet_multi_ggx_common_setup(sc);
@@ -410,6 +409,10 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderC
*eval *= *pdf;
*omega_in = X*localO.x + Y*localO.y + Z*localO.z;
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx;
+ *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy;
+#endif
return LABEL_REFLECT|LABEL_GLOSSY;
}
@@ -467,10 +470,23 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const S
*eval *= *pdf;
*omega_in = X*localO.x + Y*localO.y + Z*localO.z;
- if(localO.z*localI.z > 0.0f)
+ if(localO.z*localI.z > 0.0f) {
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx;
+ *domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy;
+#endif
return LABEL_REFLECT|LABEL_GLOSSY;
- else
+ }
+ else {
+#ifdef __RAY_DIFFERENTIALS__
+ float cosI = dot(Z, I);
+ float dnp = max(sqrtf(1.0f - (sc->data2 * sc->data2 * (1.0f - cosI*cosI))), 1e-7f);
+ *domega_in_dx = -(sc->data2 * dIdx) + ((sc->data2 - sc->data2 * sc->data2 * cosI / dnp) * dot(dIdx, Z)) * Z;
+ *domega_in_dy = -(sc->data2 * dIdy) + ((sc->data2 - sc->data2 * sc->data2 * cosI / dnp) * dot(dIdy, Z)) * Z;
+#endif
+
return LABEL_TRANSMIT|LABEL_GLOSSY;
+ }
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h
index 89b1998d1ce..b0c5280b6cb 100644
--- a/intern/cycles/kernel/closure/bsdf_util.h
+++ b/intern/cycles/kernel/closure/bsdf_util.h
@@ -80,7 +80,7 @@ ccl_device float fresnel_dielectric(
return 1; // total internal reflection
}
else {
- float dnp = sqrtf(arg);
+ float dnp = max(sqrtf(arg), 1e-7f);
float nK = (neta * cos)- dnp;
*T = -(neta * I)+(nK * Nn);
#ifdef __RAY_DIFFERENTIALS__
diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h
index 2fb8e219884..dabba3fb1f0 100644
--- a/intern/cycles/kernel/geom/geom_motion_triangle.h
+++ b/intern/cycles/kernel/geom/geom_motion_triangle.h
@@ -387,6 +387,12 @@ ccl_device_inline void motion_triangle_intersect_subsurface(
float t, u, v;
if(ray_triangle_intersect_uv(P, dir, tmax, verts[2], verts[0], verts[1], &u, &v, &t)) {
+ for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) {
+ if(ss_isect->hits[i].t == t) {
+ return;
+ }
+ }
+
ss_isect->num_hits++;
int hit;
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
index fc081bda525..eb0decc800b 100644
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h
@@ -255,6 +255,13 @@ ccl_device_inline void triangle_intersect_subsurface(
/* Normalize U, V, W, and T. */
const float inv_det = 1.0f / det;
+ const float t = T * inv_det;
+ for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) {
+ if(ss_isect->hits[i].t == t) {
+ return;
+ }
+ }
+
ss_isect->num_hits++;
int hit;
@@ -277,7 +284,7 @@ ccl_device_inline void triangle_intersect_subsurface(
isect->type = PRIMITIVE_TRIANGLE;
isect->u = U * inv_det;
isect->v = V * inv_det;
- isect->t = T * inv_det;
+ isect->t = t;
/* Record geometric normal. */
/* TODO(sergey): Use float4_to_float3() on just an edges. */
@@ -335,9 +342,16 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
float3 qvec = cross(tvec, edge1);
float3 pvec = cross(D, edge2);
- float rt = dot(edge2, qvec) / dot(edge1, pvec);
-
- P = P + D*rt;
+ float det = dot(edge1, pvec);
+ if(det != 0.0f) {
+ /* If determinant is zero it means ray lies in the plane of
+ * the triangle. It is possible in theory due to watertight
+ * nature of triangle intersection. For suc hcases we simply
+ * don't refine intersection hoping it'll go all fine.
+ */
+ float rt = dot(edge2, qvec) / det;
+ P = P + D*rt;
+ }
if(isect->object != OBJECT_NONE) {
# ifdef __OBJECT_MOTION__
@@ -393,9 +407,16 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
float3 qvec = cross(tvec, edge1);
float3 pvec = cross(D, edge2);
- float rt = dot(edge2, qvec) / dot(edge1, pvec);
-
- P = P + D*rt;
+ float det = dot(edge1, pvec);
+ if(det != 0.0f) {
+ /* If determinant is zero it means ray lies in the plane of
+ * the triangle. It is possible in theory due to watertight
+ * nature of triangle intersection. For such cases we simply
+ * don't refine intersection hoping it'll go all fine.
+ */
+ float rt = dot(edge2, qvec) / det;
+ P = P + D*rt;
+ }
#endif /* __INTERSECTION_REFINE__ */
if(isect->object != OBJECT_NONE) {
diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
index 5f5a3609ded..0e13b22bd2c 100644
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ b/intern/cycles/kernel/kernel_accumulate.h
@@ -50,7 +50,7 @@ ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 v
else
eval->diffuse = value;
#else
- *eval = value;
+ eval->diffuse = value;
#endif
}
@@ -80,7 +80,7 @@ void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value)
else
eval->diffuse += value;
#else
- *eval += value;
+ eval->diffuse += value;
#endif
}
@@ -98,7 +98,7 @@ ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval)
else
return is_zero(eval->diffuse);
#else
- return is_zero(*eval);
+ return is_zero(eval->diffuse);
#endif
}
@@ -117,7 +117,7 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value)
else
eval->diffuse *= value;
#else
- *eval *= value;
+ eval->diffuse *= value;
#endif
}
@@ -172,7 +172,7 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
else
L->emission = make_float3(0.0f, 0.0f, 0.0f);
#else
- *L = make_float3(0.0f, 0.0f, 0.0f);
+ L->emission = make_float3(0.0f, 0.0f, 0.0f);
#endif
}
@@ -207,7 +207,7 @@ ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space
else
*throughput *= bsdf_eval->diffuse*inverse_pdf;
#else
- *throughput *= *bsdf_eval*inverse_pdf;
+ *throughput *= bsdf_eval->diffuse*inverse_pdf;
#endif
}
@@ -225,7 +225,7 @@ ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 thro
else
L->emission += throughput*value;
#else
- *L += throughput*value;
+ L->emission += throughput*value;
#endif
}
@@ -246,7 +246,7 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput
else
L->emission += throughput*bsdf*ao;
#else
- *L += throughput*bsdf*ao;
+ L->emission += throughput*bsdf*ao;
#endif
}
@@ -277,7 +277,7 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 through
else
L->emission += throughput*bsdf_eval->diffuse*shadow;
#else
- *L += throughput*(*bsdf_eval)*shadow;
+ L->emission += throughput*bsdf_eval->diffuse*shadow;
#endif
}
@@ -295,7 +295,7 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 th
else
L->emission += throughput*value;
#else
- *L += throughput*value;
+ L->emission += throughput*value;
#endif
}
@@ -441,7 +441,7 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi
else
L_sum = L->emission;
#else
- L_sum = *L;
+ L_sum = L->emission;
#endif
/* Reject invalid value */
@@ -477,7 +477,7 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance
L->shadow += L_sample->shadow*fac;
L->mist += L_sample->mist*fac;
#else
- *L += *L_sample * fac;
+ L->emission += L_sample->emission * fac;
#endif
}
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index db2fc84834a..d1576754d2e 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -75,7 +75,12 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd,
}
uint num_hits;
- blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits);
+ if(max_hits == 0) {
+ blocked = true;
+ num_hits = 0;
+ } else {
+ blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits);
+ }
/* if no opaque surface found but we did find transparent hits, shade them */
if(!blocked && num_hits > 0) {
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 5de58ba28ed..a9be2ae717a 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -387,12 +387,13 @@ typedef enum BakePassFilterCombos {
BAKE_FILTER_SUBSURFACE_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_SUBSURFACE),
} BakePassFilterCombos;
-#ifdef __PASSES__
-
typedef ccl_addr_space struct PathRadiance {
+#ifdef __PASSES__
int use_light_pass;
+#endif
float3 emission;
+#ifdef __PASSES__
float3 background;
float3 ao;
@@ -426,25 +427,23 @@ typedef ccl_addr_space struct PathRadiance {
float4 shadow;
float mist;
+#endif
} PathRadiance;
typedef struct BsdfEval {
+#ifdef __PASSES__
int use_light_pass;
+#endif
float3 diffuse;
+#ifdef __PASSES__
float3 glossy;
float3 transmission;
float3 transparent;
float3 subsurface;
float3 scatter;
-} BsdfEval;
-
-#else
-
-typedef ccl_addr_space float3 PathRadiance;
-typedef float3 BsdfEval;
-
#endif
+} BsdfEval;
/* Shader Flag */
diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h
index 962196ccbdd..ec82d4b4c22 100644
--- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h
+++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h
@@ -109,6 +109,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg,
{
if(type >= SHADER_EVAL_BAKE) {
kernel_assert(output_luma == NULL);
+#ifdef __BAKING__
kernel_bake_evaluate(kg,
input,
output,
@@ -117,6 +118,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg,
i,
offset,
sample);
+#endif
}
else {
kernel_shader_evaluate(kg,
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index 27fed89fdf7..276b6f26f5e 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -312,7 +312,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
/* apply normal map */
float3 B = sign * cross(normal, tangent);
- N = normalize(color.x * tangent + color.y * B + color.z * normal);
+ N = safe_normalize(color.x * tangent + color.y * B + color.z * normal);
/* transform to world space */
object_normal_transform(kg, sd, &N);
@@ -330,14 +330,18 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
if(space == NODE_NORMAL_MAP_OBJECT || space == NODE_NORMAL_MAP_BLENDER_OBJECT)
object_normal_transform(kg, sd, &N);
else
- N = normalize(N);
+ N = safe_normalize(N);
}
float strength = stack_load_float(stack, strength_offset);
if(strength != 1.0f) {
strength = max(strength, 0.0f);
- N = normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength);
+ N = safe_normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength);
+ }
+
+ if(is_zero(N)) {
+ N = ccl_fetch(sd, N);
}
stack_store_float3(stack, normal_offset, N);
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index b14da3e63d0..a632ddc0598 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -22,6 +22,7 @@ set(SRC
bake.cpp
buffers.cpp
camera.cpp
+ constant_fold.cpp
film.cpp
graph.cpp
image.cpp
@@ -49,6 +50,7 @@ set(SRC_HEADERS
background.h
buffers.h
camera.h
+ constant_fold.h
film.h
graph.h
image.h
diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp
new file mode 100644
index 00000000000..1fee6b2c081
--- /dev/null
+++ b/intern/cycles/render/constant_fold.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "constant_fold.h"
+#include "graph.h"
+
+#include "util_foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+ConstantFolder::ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output)
+: graph(graph), node(node), output(output)
+{
+}
+
+bool ConstantFolder::all_inputs_constant() const
+{
+ foreach(ShaderInput *input, node->inputs) {
+ if(input->link) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ConstantFolder::make_constant(float value) const
+{
+ foreach(ShaderInput *sock, output->links) {
+ sock->set(value);
+ }
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::make_constant(float3 value) const
+{
+ foreach(ShaderInput *sock, output->links) {
+ sock->set(value);
+ }
+
+ graph->disconnect(output);
+}
+
+void ConstantFolder::make_constant_clamp(float value, bool clamp) const
+{
+ make_constant(clamp ? saturate(value) : value);
+}
+
+void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const
+{
+ if (clamp) {
+ value.x = saturate(value.x);
+ value.y = saturate(value.y);
+ value.z = saturate(value.z);
+ }
+
+ make_constant(value);
+}
+
+void ConstantFolder::bypass(ShaderOutput *new_output) const
+{
+ assert(new_output);
+
+ /* Remove all outgoing links from socket and connect them to new_output instead.
+ * The graph->relink method affects node inputs, so it's not safe to use in constant
+ * folding if the node has multiple outputs and will thus be folded multiple times. */
+ vector<ShaderInput*> outputs = output->links;
+
+ graph->disconnect(output);
+
+ foreach(ShaderInput *sock, outputs) {
+ graph->connect(new_output, sock);
+ }
+}
+
+void ConstantFolder::discard() const
+{
+ assert(output->type() == SocketType::CLOSURE);
+ graph->disconnect(output);
+}
+
+void ConstantFolder::bypass_or_discard(ShaderInput *input) const
+{
+ assert(input->type() == SocketType::CLOSURE);
+
+ if (input->link) {
+ bypass(input->link);
+ }
+ else {
+ discard();
+ }
+}
+
+bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, float3 input_value, bool clamp) const
+{
+ if(!input->link) {
+ make_constant_clamp(input_value, clamp);
+ return true;
+ }
+ else if(!clamp) {
+ bypass(input->link);
+ return true;
+ }
+
+ return false;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h
new file mode 100644
index 00000000000..978c8e5335a
--- /dev/null
+++ b/intern/cycles/render/constant_fold.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CONSTANT_FOLD_H__
+#define __CONSTANT_FOLD_H__
+
+#include "util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+class ShaderGraph;
+class ShaderInput;
+class ShaderNode;
+class ShaderOutput;
+
+class ConstantFolder {
+public:
+ ShaderGraph *const graph;
+ ShaderNode *const node;
+ ShaderOutput *const output;
+
+ ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output);
+
+ bool all_inputs_constant() const;
+
+ /* Constant folding helpers, always return true for convenience. */
+ void make_constant(float value) const;
+ void make_constant(float3 value) const;
+ void make_constant_clamp(float value, bool clamp) const;
+ void make_constant_clamp(float3 value, bool clamp) const;
+
+ /* Bypass node, relinking to another output socket. */
+ void bypass(ShaderOutput *output) const;
+
+ /* For closure nodes, discard node entirely or bypass to one of its inputs. */
+ void discard() const;
+ void bypass_or_discard(ShaderInput *input) const;
+
+ /* Bypass or make constant, unless we can't due to clamp being true. */
+ bool try_bypass_or_make_constant(ShaderInput *input, float3 input_value, bool clamp) const;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __CONSTANT_FOLD_H__ */
+
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index fd48bf2631e..66601fa3502 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 Blender Foundation
+ * Copyright 2011-2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
#include "graph.h"
#include "nodes.h"
#include "shader.h"
+#include "constant_fold.h"
#include "util_algorithm.h"
#include "util_debug.h"
@@ -126,17 +127,6 @@ ShaderOutput *ShaderNode::output(ustring name)
return NULL;
}
-bool ShaderNode::all_inputs_constant() const
-{
- foreach(ShaderInput *input, inputs) {
- if(input->link) {
- return false;
- }
- }
-
- return true;
-}
-
void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
foreach(ShaderInput *input, inputs) {
@@ -278,6 +268,17 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to)
}
}
+void ShaderGraph::disconnect(ShaderOutput *from)
+{
+ assert(!finalized);
+
+ foreach(ShaderInput *sock, from->links) {
+ sock->link = NULL;
+ }
+
+ from->links.clear();
+}
+
void ShaderGraph::disconnect(ShaderInput *to)
{
assert(!finalized);
@@ -373,24 +374,12 @@ void ShaderGraph::copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap)
ShaderNode *nnode = node->clone();
nnodemap[node] = nnode;
+ /* create new inputs and outputs to recreate links and ensure
+ * that we still point to valid SocketType if the NodeType
+ * changed in cloning, as it does for OSL nodes */
nnode->inputs.clear();
nnode->outputs.clear();
-
- foreach(ShaderInput *input, node->inputs) {
- ShaderInput *ninput = new ShaderInput(*input);
- nnode->inputs.push_back(ninput);
-
- ninput->parent = nnode;
- ninput->link = NULL;
- }
-
- foreach(ShaderOutput *output, node->outputs) {
- ShaderOutput *noutput = new ShaderOutput(*output);
- nnode->outputs.push_back(noutput);
-
- noutput->parent = nnode;
- noutput->links.clear();
- }
+ nnode->create_inputs_outputs(nnode->type);
}
/* recreate links */
@@ -525,15 +514,8 @@ void ShaderGraph::constant_fold()
}
}
/* Optimize current node. */
- if(node->constant_fold(this, output, output->links[0])) {
- /* Apply optimized value to other connected sockets and disconnect. */
- vector<ShaderInput*> links(output->links);
- for(size_t i = 0; i < links.size(); i++) {
- if(i > 0)
- links[i]->parent->copy_value(links[i]->socket_type, *links[0]->parent, links[0]->socket_type);
- disconnect(links[i]);
- }
- }
+ ConstantFolder folder(this, node, output);
+ node->constant_fold(folder);
}
}
}
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index 61100cda60b..b35be48d8ca 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 Blender Foundation
+ * Copyright 2011-2016 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@ class ShaderGraph;
class SVMCompiler;
class OSLCompiler;
class OutputNode;
+class ConstantFolder;
/* Bump
*
@@ -140,9 +141,7 @@ public:
/* ** Node optimization ** */
/* Check whether the node can be replaced with single constant. */
- virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, ShaderInput * /*optimized*/) { return false; }
-
- bool all_inputs_constant() const;
+ virtual void constant_fold(const ConstantFolder& /*folder*/) {}
/* Simplify settings used by artists to the ones which are simpler to
* evaluate in the kernel but keep the final result unchanged.
@@ -251,6 +250,7 @@ public:
OutputNode *output();
void connect(ShaderOutput *from, ShaderInput *to);
+ void disconnect(ShaderOutput *from);
void disconnect(ShaderInput *to);
void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to);
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index 2a10eb474a4..63914e57319 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -176,7 +176,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
max_samples = max(max_samples, volume_samples);
}
- max_samples *= (max_bounce + transparent_max_bounce + 3);
+ max_samples *= (max_bounce + transparent_max_bounce + 3 + BSSRDF_MAX_HITS);
int dimensions = PRNG_BASE_NUM + max_samples*PRNG_BOUNCE_NUM;
dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS);
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 661719ed545..8b0ed9f77b2 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -588,7 +588,8 @@ void Mesh::compute_bvh(DeviceScene *dscene,
BVHParams bparams;
bparams.use_spatial_split = params->use_bvh_spatial_split;
bparams.use_qbvh = params->use_qbvh;
- bparams.use_unaligned_nodes = dscene->data.bvh.have_curves;
+ bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
+ params->use_bvh_unaligned_nodes;
delete bvh;
bvh = BVH::create(bparams, objects);
@@ -1222,7 +1223,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *
bparams.top_level = true;
bparams.use_qbvh = scene->params.use_qbvh;
bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
- bparams.use_unaligned_nodes = dscene->data.bvh.have_curves;
+ bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
+ scene->params.use_bvh_unaligned_nodes;
delete bvh;
bvh = BVH::create(bparams, scene->objects);
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 15b55d17301..e26084c690b 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -22,6 +22,7 @@
#include "svm_color_util.h"
#include "svm_math_util.h"
#include "osl.h"
+#include "constant_fold.h"
#include "util_sky_model.h"
#include "util_foreach.h"
@@ -1576,14 +1577,11 @@ RGBToBWNode::RGBToBWNode()
{
}
-bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void RGBToBWNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
- optimized->set(linear_rgb_to_gray(color));
- return true;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(linear_rgb_to_gray(color));
}
-
- return false;
}
void RGBToBWNode::compile(SVMCompiler& compiler)
@@ -1661,38 +1659,35 @@ ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool auto
special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
}
-bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void ConvertNode::constant_fold(const ConstantFolder& folder)
{
/* proxy nodes should have been removed at this point */
assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
/* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
- if(all_inputs_constant()) {
+ if(folder.all_inputs_constant()) {
if(from == SocketType::FLOAT) {
if(SocketType::is_float3(to)) {
- optimized->set(make_float3(value_float, value_float, value_float));
- return true;
+ folder.make_constant(make_float3(value_float, value_float, value_float));
}
}
else if(SocketType::is_float3(from)) {
if(to == SocketType::FLOAT) {
- if(from == SocketType::COLOR)
+ if(from == SocketType::COLOR) {
/* color to float */
- optimized->set(linear_rgb_to_gray(value_color));
- else
+ folder.make_constant(linear_rgb_to_gray(value_color));
+ }
+ else {
/* vector/point/normal to float */
- optimized->set(average(value_vector));
- return true;
+ folder.make_constant(average(value_vector));
+ }
}
else if(SocketType::is_float3(to)) {
- optimized->set(value_color);
- return true;
+ folder.make_constant(value_color);
}
}
}
-
- return false;
}
void ConvertNode::compile(SVMCompiler& compiler)
@@ -2362,13 +2357,15 @@ void EmissionNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_emission");
}
-bool EmissionNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *)
+void EmissionNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
- return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!strength_in->link && strength == 0.0f));
+ if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
+ (!strength_in->link && strength == 0.0f)) {
+ folder.discard();
+ }
}
/* Background Closure */
@@ -2412,13 +2409,15 @@ void BackgroundNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_background");
}
-bool BackgroundNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *)
+void BackgroundNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *color_in = input("Color");
ShaderInput *strength_in = input("Strength");
- return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
- (!strength_in->link && strength == 0.0f));
+ if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
+ (!strength_in->link && strength == 0.0f)) {
+ folder.discard();
+ }
}
/* Holdout Closure */
@@ -3380,10 +3379,9 @@ ValueNode::ValueNode()
{
}
-bool ValueNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void ValueNode::constant_fold(const ConstantFolder& folder)
{
- optimized->set(value);
- return true;
+ folder.make_constant(value);
}
void ValueNode::compile(SVMCompiler& compiler)
@@ -3416,10 +3414,9 @@ ColorNode::ColorNode()
{
}
-bool ColorNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void ColorNode::constant_fold(const ConstantFolder& folder)
{
- optimized->set(value);
- return true;
+ folder.make_constant(value);
}
void ColorNode::compile(SVMCompiler& compiler)
@@ -3468,6 +3465,20 @@ void AddClosureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_add_closure");
}
+void AddClosureNode::constant_fold(const ConstantFolder& folder)
+{
+ ShaderInput *closure1_in = input("Closure1");
+ ShaderInput *closure2_in = input("Closure2");
+
+ /* remove useless add closures nodes */
+ if(!closure1_in->link) {
+ folder.bypass_or_discard(closure2_in);
+ }
+ else if(!closure2_in->link) {
+ folder.bypass_or_discard(closure1_in);
+ }
+}
+
/* Mix Closure */
NODE_DEFINE(MixClosureNode)
@@ -3499,35 +3510,28 @@ void MixClosureNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_mix_closure");
}
-bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *)
+void MixClosureNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *fac_in = input("Fac");
ShaderInput *closure1_in = input("Closure1");
ShaderInput *closure2_in = input("Closure2");
- ShaderOutput *closure_out = output("Closure");
/* remove useless mix closures nodes */
if(closure1_in->link == closure2_in->link) {
- graph->relink(this, closure_out, closure1_in->link);
- return true;
+ folder.bypass_or_discard(closure1_in);
}
-
- /* remove unused mix closure input when factor is 0.0 or 1.0 */
- /* check for closure links and make sure factor link is disconnected */
- if(closure1_in->link && closure2_in->link && !fac_in->link) {
+ /* remove unused mix closure input when factor is 0.0 or 1.0
+ * check for closure links and make sure factor link is disconnected */
+ else if(!fac_in->link) {
/* factor 0.0 */
- if(fac == 0.0f) {
- graph->relink(this, closure_out, closure1_in->link);
- return true;
+ if(fac <= 0.0f) {
+ folder.bypass_or_discard(closure1_in);
}
/* factor 1.0 */
- else if(fac == 1.0f) {
- graph->relink(this, closure_out, closure2_in->link);
- return true;
+ else if(fac >= 1.0f) {
+ folder.bypass_or_discard(closure2_in);
}
}
-
- return false;
}
/* Mix Closure */
@@ -3589,26 +3593,21 @@ InvertNode::InvertNode()
{
}
-bool InvertNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized)
+void InvertNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *fac_in = input("Fac");
ShaderInput *color_in = input("Color");
- ShaderOutput *color_out = output("Color");
if(!fac_in->link) {
/* evaluate fully constant node */
if(!color_in->link) {
- optimized->set(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac));
- return true;
+ folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac));
}
/* remove no-op node */
else if(fac == 0.0f) {
- graph->relink(this, color_out, color_in->link);
- return true;
+ folder.bypass(color_in->link);
}
}
-
- return false;
}
void InvertNode::compile(SVMCompiler& compiler)
@@ -3697,61 +3696,47 @@ void MixNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_mix");
}
-bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized)
+void MixNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *fac_in = input("Fac");
ShaderInput *color1_in = input("Color1");
ShaderInput *color2_in = input("Color2");
- ShaderOutput *color_out = output("Color");
/* evaluate fully constant node */
- if(all_inputs_constant()) {
- float3 result = svm_mix(type, fac, color1, color2);
- optimized->set(use_clamp ? svm_mix_clamp(result) : result);
- return true;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp);
+ return;
}
/* remove no-op node when factor is 0.0 */
if(!fac_in->link && fac <= 0.0f) {
/* note that some of the modes will clamp out of bounds values even without use_clamp */
- if(!color1_in->link) {
- float3 result = svm_mix(type, 0.0f, color1, color1);
- optimized->set(use_clamp ? svm_mix_clamp(result) : result);
- return true;
+ if(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN) {
+ if(!color1_in->link) {
+ folder.make_constant_clamp(svm_mix(type, 0.0f, color1, color1), use_clamp);
+ return;
+ }
}
- else if(!use_clamp && type != NODE_MIX_LIGHT && type != NODE_MIX_DODGE && type != NODE_MIX_BURN) {
- graph->relink(this, color_out, color1_in->link);
- return true;
+ else if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) {
+ return;
}
}
- if(type != NODE_MIX_BLEND) {
- return false;
- }
-
- /* remove useless mix colors nodes */
- if(color1_in->link && color1_in->link == color2_in->link && !use_clamp) {
- graph->relink(this, color_out, color1_in->link);
- return true;
- }
- if(!color1_in->link && !color2_in->link && color1 == color2) {
- optimized->set(use_clamp ? svm_mix_clamp(color1) : color1);
- return true;
- }
-
- /* remove no-op mix color node when factor is 1.0 */
- if(!fac_in->link && fac >= 1.0f) {
- if(!color2_in->link) {
- optimized->set(use_clamp ? svm_mix_clamp(color2) : color2);
- return true;
+ if(type == NODE_MIX_BLEND) {
+ /* remove useless mix colors nodes */
+ if(color1_in->link ? (color1_in->link == color2_in->link) : (!color2_in->link && color1 == color2)) {
+ if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) {
+ return;
+ }
}
- else if(!use_clamp) {
- graph->relink(this, color_out, color2_in->link);
- return true;
+
+ /* remove no-op mix color node when factor is 1.0 */
+ if(!fac_in->link && fac >= 1.0f) {
+ if(folder.try_bypass_or_make_constant(color2_in, color2, use_clamp)) {
+ return;
+ }
}
}
-
- return false;
}
/* Combine RGB */
@@ -3774,14 +3759,11 @@ CombineRGBNode::CombineRGBNode()
{
}
-bool CombineRGBNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void CombineRGBNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
- optimized->set(make_float3(r, g, b));
- return true;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(make_float3(r, g, b));
}
-
- return false;
}
void CombineRGBNode::compile(SVMCompiler& compiler)
@@ -3829,14 +3811,11 @@ CombineXYZNode::CombineXYZNode()
{
}
-bool CombineXYZNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void CombineXYZNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
- optimized->set(make_float3(x, y, z));
- return true;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(make_float3(x, y, z));
}
-
- return false;
}
void CombineXYZNode::compile(SVMCompiler& compiler)
@@ -3884,14 +3863,11 @@ CombineHSVNode::CombineHSVNode()
{
}
-bool CombineHSVNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void CombineHSVNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
- optimized->set(hsv_to_rgb(make_float3(h, s, v)));
- return true;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(hsv_to_rgb(make_float3(h, s, v)));
}
-
- return false;
}
void CombineHSVNode::compile(SVMCompiler& compiler)
@@ -3932,14 +3908,11 @@ GammaNode::GammaNode()
{
}
-bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void GammaNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
- optimized->set(svm_math_gamma_color(color, gamma));
- return true;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(svm_math_gamma_color(color, gamma));
}
-
- return false;
}
void GammaNode::compile(SVMCompiler& compiler)
@@ -3979,14 +3952,11 @@ BrightContrastNode::BrightContrastNode()
{
}
-bool BrightContrastNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void BrightContrastNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
- optimized->set(svm_brightness_contrast(color, bright, contrast));
- return true;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(svm_brightness_contrast(color, bright, contrast));
}
-
- return false;
}
void BrightContrastNode::compile(SVMCompiler& compiler)
@@ -4029,18 +3999,16 @@ SeparateRGBNode::SeparateRGBNode()
{
}
-bool SeparateRGBNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
+void SeparateRGBNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
+ if(folder.all_inputs_constant()) {
for(int channel = 0; channel < 3; channel++) {
- if(outputs[channel] == socket) {
- optimized->set(color[channel]);
- return true;
+ if(outputs[channel] == folder.output) {
+ folder.make_constant(color[channel]);
+ return;
}
}
}
-
- return false;
}
void SeparateRGBNode::compile(SVMCompiler& compiler)
@@ -4088,18 +4056,16 @@ SeparateXYZNode::SeparateXYZNode()
{
}
-bool SeparateXYZNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
+void SeparateXYZNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
+ if(folder.all_inputs_constant()) {
for(int channel = 0; channel < 3; channel++) {
- if(outputs[channel] == socket) {
- optimized->set(vector[channel]);
- return true;
+ if(outputs[channel] == folder.output) {
+ folder.make_constant(vector[channel]);
+ return;
}
}
}
-
- return false;
}
void SeparateXYZNode::compile(SVMCompiler& compiler)
@@ -4147,20 +4113,18 @@ SeparateHSVNode::SeparateHSVNode()
{
}
-bool SeparateHSVNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
+void SeparateHSVNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
+ if(folder.all_inputs_constant()) {
float3 hsv = rgb_to_hsv(color);
for(int channel = 0; channel < 3; channel++) {
- if(outputs[channel] == socket) {
- optimized->set(hsv[channel]);
- return true;
+ if(outputs[channel] == folder.output) {
+ folder.make_constant(hsv[channel]);
+ return;
}
}
}
-
- return false;
}
void SeparateHSVNode::compile(SVMCompiler& compiler)
@@ -4546,14 +4510,11 @@ BlackbodyNode::BlackbodyNode()
{
}
-bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void BlackbodyNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
- optimized->set(svm_math_blackbody_color(temperature));
- return true;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant(svm_math_blackbody_color(temperature));
}
-
- return false;
}
void BlackbodyNode::compile(SVMCompiler& compiler)
@@ -4655,15 +4616,11 @@ MathNode::MathNode()
{
}
-bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized)
+void MathNode::constant_fold(const ConstantFolder& folder)
{
- if(all_inputs_constant()) {
- float value = svm_math(type, value1, value2);
- optimized->set(use_clamp ? saturate(value) : value);
- return true;
+ if(folder.all_inputs_constant()) {
+ folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp);
}
-
- return false;
}
void MathNode::compile(SVMCompiler& compiler)
@@ -4717,29 +4674,25 @@ VectorMathNode::VectorMathNode()
{
}
-bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized)
+void VectorMathNode::constant_fold(const ConstantFolder& folder)
{
float value;
float3 vector;
- if(all_inputs_constant()) {
+ if(folder.all_inputs_constant()) {
svm_vector_math(&value,
&vector,
type,
vector1,
vector2);
- if(socket == output("Value")) {
- optimized->set(value);
- return true;
+ if(folder.output == output("Value")) {
+ folder.make_constant(value);
}
- else if(socket == output("Vector")) {
- optimized->set(vector);
- return true;
+ else if(folder.output == output("Vector")) {
+ folder.make_constant(vector);
}
}
-
- return false;
}
void VectorMathNode::compile(SVMCompiler& compiler)
@@ -4873,7 +4826,7 @@ void BumpNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_bump");
}
-bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *)
+void BumpNode::constant_fold(const ConstantFolder& folder)
{
ShaderInput *height_in = input("Height");
ShaderInput *normal_in = input("Normal");
@@ -4881,18 +4834,15 @@ bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *)
if(height_in->link == NULL) {
if(normal_in->link == NULL) {
GeometryNode *geom = new GeometryNode();
- graph->add(geom);
- graph->relink(this, outputs[0], geom->output("Normal"));
+ folder.graph->add(geom);
+ folder.bypass(geom->output("Normal"));
}
else {
- graph->relink(this, outputs[0], normal_in->link);
+ folder.bypass(normal_in->link);
}
- return true;
}
/* TODO(sergey): Ignore bump with zero strength. */
-
- return false;
}
@@ -5112,12 +5062,10 @@ OSLNode::~OSLNode()
ShaderNode *OSLNode::clone() const
{
- OSLNode *node = new OSLNode(*this);
- node->type = new NodeType(*type);
- return node;
+ return OSLNode::create(this->inputs.size(), this);
}
-OSLNode* OSLNode::create(size_t num_inputs)
+OSLNode* OSLNode::create(size_t num_inputs, const OSLNode *from)
{
/* allocate space for the node itself and parameters, aligned to 16 bytes
* assuming that's the most parameter types need */
@@ -5127,7 +5075,17 @@ OSLNode* OSLNode::create(size_t num_inputs)
char *node_memory = (char*) operator new(node_size + inputs_size);
memset(node_memory, 0, node_size + inputs_size);
- return new(node_memory) OSLNode();
+ if (!from) {
+ return new(node_memory) OSLNode();
+ }
+ else {
+ /* copy input default values and node type for cloning */
+ memcpy(node_memory + node_size, (char*)from + node_size, inputs_size);
+
+ OSLNode *node = new(node_memory) OSLNode(*from);
+ node->type = new NodeType(*(from->type));
+ return node;
+ }
}
char* OSLNode::input_default_value()
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 3245fdfb6d9..caad11af0f8 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -289,7 +289,7 @@ public:
class RGBToBWNode : public ShaderNode {
public:
SHADER_NODE_CLASS(RGBToBWNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
float3 color;
};
@@ -299,7 +299,7 @@ public:
ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false);
SHADER_NODE_BASE_CLASS(ConvertNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
SocketType::Type from, to;
@@ -436,7 +436,7 @@ public:
class EmissionNode : public ShaderNode {
public:
SHADER_NODE_CLASS(EmissionNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; }
bool has_surface_emission() { return true; }
@@ -449,7 +449,7 @@ public:
class BackgroundNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BackgroundNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; }
float3 color;
@@ -605,7 +605,7 @@ class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
float value;
};
@@ -614,7 +614,7 @@ class ColorNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ColorNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
float3 value;
};
@@ -622,12 +622,13 @@ public:
class AddClosureNode : public ShaderNode {
public:
SHADER_NODE_CLASS(AddClosureNode)
+ void constant_fold(const ConstantFolder& folder);
};
class MixClosureNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixClosureNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
float fac;
};
@@ -643,7 +644,7 @@ public:
class InvertNode : public ShaderNode {
public:
SHADER_NODE_CLASS(InvertNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
float fac;
@@ -653,7 +654,7 @@ public:
class MixNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MixNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
@@ -667,7 +668,7 @@ public:
class CombineRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineRGBNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
float r, g, b;
@@ -676,7 +677,7 @@ public:
class CombineHSVNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineHSVNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
float h, s, v;
@@ -685,7 +686,7 @@ public:
class CombineXYZNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineXYZNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
float x, y, z;
@@ -694,7 +695,7 @@ public:
class GammaNode : public ShaderNode {
public:
SHADER_NODE_CLASS(GammaNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
float3 color;
@@ -704,7 +705,7 @@ public:
class BrightContrastNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BrightContrastNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
float3 color;
@@ -715,7 +716,7 @@ public:
class SeparateRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateRGBNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
float3 color;
@@ -724,7 +725,7 @@ public:
class SeparateHSVNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateHSVNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
float3 color;
@@ -733,7 +734,7 @@ public:
class SeparateXYZNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateXYZNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
float3 vector;
@@ -806,7 +807,7 @@ public:
class BlackbodyNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BlackbodyNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
float temperature;
@@ -816,7 +817,7 @@ class MathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
float value1;
float value2;
@@ -837,7 +838,7 @@ class VectorMathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorMathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
float3 vector1;
float3 vector2;
@@ -859,7 +860,7 @@ public:
class BumpNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BumpNode)
- bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized);
+ void constant_fold(const ConstantFolder& folder);
bool has_spatial_varying() { return true; }
virtual int get_feature() {
return NODE_FEATURE_BUMP;
@@ -920,7 +921,7 @@ public:
class OSLNode : public ShaderNode {
public:
- static OSLNode *create(size_t num_inputs);
+ static OSLNode *create(size_t num_inputs, const OSLNode *from = NULL);
~OSLNode();
ShaderNode *clone() const;
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index ff1f678c2d2..662d87e8b6b 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -184,7 +184,7 @@ void Object::apply_transform(bool apply_to_motion)
}
/* tfm is not reset to identity, all code that uses it needs to check the
- transform_applied boolean */
+ * transform_applied boolean */
}
void Object::tag_update(Scene *scene)
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index e8367e1eb36..b341837b7e8 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -263,6 +263,14 @@ Scene::MotionType Scene::need_motion(bool advanced_shading)
return MOTION_NONE;
}
+float Scene::motion_shutter_time()
+{
+ if(need_motion() == Scene::MOTION_PASS)
+ return 2.0f;
+ else
+ return camera->shuttertime;
+}
+
bool Scene::need_global_attribute(AttributeStandard std)
{
if(std == ATTR_STD_UV)
diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h
index 925e84ad96d..05e807ff60c 100644
--- a/intern/cycles/render/scene.h
+++ b/intern/cycles/render/scene.h
@@ -136,6 +136,7 @@ public:
BVH_NUM_TYPES,
} bvh_type;
bool use_bvh_spatial_split;
+ bool use_bvh_unaligned_nodes;
bool use_qbvh;
bool persistent_data;
@@ -144,6 +145,7 @@ public:
shadingsystem = SHADINGSYSTEM_SVM;
bvh_type = BVH_DYNAMIC;
use_bvh_spatial_split = false;
+ use_bvh_unaligned_nodes = true;
use_qbvh = false;
persistent_data = false;
}
@@ -152,6 +154,7 @@ public:
{ return !(shadingsystem == params.shadingsystem
&& bvh_type == params.bvh_type
&& use_bvh_spatial_split == params.use_bvh_spatial_split
+ && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes
&& use_qbvh == params.use_qbvh
&& persistent_data == params.persistent_data); }
};
@@ -210,6 +213,7 @@ public:
enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR };
MotionType need_motion(bool advanced_shading = true);
+ float motion_shutter_time();
bool need_update();
bool need_reset();
diff --git a/intern/cycles/util/util_math_fast.h b/intern/cycles/util/util_math_fast.h
index deb2013daae..d3960deb3b4 100644
--- a/intern/cycles/util/util_math_fast.h
+++ b/intern/cycles/util/util_math_fast.h
@@ -547,6 +547,9 @@ ccl_device_inline float fast_erff(float x)
const float a5 = 0.0002765672f;
const float a6 = 0.0000430638f;
const float a = fabsf(x);
+ if(a >= 12.3f) {
+ return copysignf(1.0f, x);
+ }
const float b = 1.0f - (1.0f - a); /* Crush denormals. */
const float r = madd(madd(madd(madd(madd(madd(a6, b, a5), b, a4), b, a3), b, a2), b, a1), b, 1.0f);
const float s = r * r; /* ^2 */
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 7e77ba3a41f..0dd5d15b011 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -530,7 +530,7 @@ typedef struct {
#ifdef _WIN32
-typedef long GHOST_TEmbedderWindowID;
+typedef void* GHOST_TEmbedderWindowID;
#endif // _WIN32
#ifndef _WIN32
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index eeb6a2469ee..abce3ea6588 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -707,6 +707,7 @@ int GHOST_ContextWGL::choose_pixel_format(
PIXELFORMATDESCRIPTOR preferredPFD = {
sizeof(PIXELFORMATDESCRIPTOR), /* size */
1, /* version */
+ (DWORD) (
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_SWAP_COPY | /* support swap copy */
@@ -717,16 +718,16 @@ int GHOST_ContextWGL::choose_pixel_format(
needAlpha ? PFD_SUPPORT_COMPOSITION : /* support composition for transparent background */
#endif
0
- ),
+ )),
PFD_TYPE_RGBA, /* color type */
- (needAlpha ? 32 : 24), /* preferred color depth */
+ (BYTE) (needAlpha ? 32 : 24), /* preferred color depth */
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
- needAlpha ? 8 : 0, /* alpha buffer */
+ (BYTE) (needAlpha ? 8 : 0), /* alpha buffer */
0, /* alpha shift (ignored) */
0, /* no accumulation buffer */
0, 0, 0, 0, /* accum bits (ignored) */
24, /* depth buffer */
- needStencil ? 8 : 0, /* stencil buffer */
+ (BYTE) (needStencil ? 8 : 0), /* stencil buffer */
0, /* no auxiliary buffers */
PFD_MAIN_PLANE, /* main layer */
0, /* reserved */
diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp
index af5a2ed7097..96bd12faef8 100644
--- a/intern/ghost/intern/GHOST_ImeWin32.cpp
+++ b/intern/ghost/intern/GHOST_ImeWin32.cpp
@@ -64,7 +64,7 @@ bool GHOST_ImeWin32::SetInputLanguage()
* while composing a text.
*/
HKL keyboard_layout = ::GetKeyboardLayout(0);
- input_language_id_ = reinterpret_cast<LANGID>(keyboard_layout);
+ input_language_id_ = LOWORD(keyboard_layout);
ime_status_ = ::ImmIsIME(keyboard_layout);
return ime_status_;
}
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 55d013f6e5f..6f349543eed 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -1985,9 +1985,8 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
);
}
#endif
-/*
+/**
* These callbacks can be used for debugging, so we can breakpoint on an X11 error.
-
*
* Dummy function to get around IO Handler exiting if device invalid
* Basically it will not crash blender now if you have a X device that
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index c9bcb38ab68..6a27d7aadf9 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -95,31 +95,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_parentWindowHwnd(parentwindowhwnd),
m_debug_context(is_debug)
{
- OSVERSIONINFOEX versionInfo;
- bool hasMinVersionForTaskbar = false;
-
- ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
-
- versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-
- if (!GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
- versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
- if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) ||
- (versionInfo.dwMajorVersion >= 7))
- {
- hasMinVersionForTaskbar = true;
- }
- }
- }
- else {
- if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) ||
- (versionInfo.dwMajorVersion >= 7))
- {
- hasMinVersionForTaskbar = true;
- }
- }
-
if (state != GHOST_kWindowStateFullScreen) {
RECT rect;
MONITORINFO monitor;
@@ -341,11 +316,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
}
}
}
-
- if (hasMinVersionForTaskbar)
- CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (LPVOID *)&m_Bar);
- else
- m_Bar = NULL;
+ CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar);
}
diff --git a/intern/guardedalloc/test/simpletest/memtest.c b/intern/guardedalloc/test/simpletest/memtest.c
index 841b47bd4f1..79d55dd02cc 100644
--- a/intern/guardedalloc/test/simpletest/memtest.c
+++ b/intern/guardedalloc/test/simpletest/memtest.c
@@ -26,7 +26,6 @@
*/
/**
-
* Copyright (C) 2001 NaN Technologies B.V.
* Simple test of memory.
*/
diff --git a/intern/libmv/intern/autotrack.cc b/intern/libmv/intern/autotrack.cc
index f0cbc68f11e..3b7c9c5a010 100644
--- a/intern/libmv/intern/autotrack.cc
+++ b/intern/libmv/intern/autotrack.cc
@@ -67,12 +67,12 @@ int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack,
libmv_apiMarkerToMarker(*libmv_tracked_marker, &tracked_marker);
libmv_configureTrackRegionOptions(*libmv_options,
&options);
- (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker,
- &result,
- &options));
+ bool ok = (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker,
+ &result,
+ &options));
libmv_markerToApiMarker(tracked_marker, libmv_tracked_marker);
libmv_regionTrackergetResult(result, libmv_result);
- return result.is_usable();
+ return ok && result.is_usable();
}
void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack,
diff --git a/intern/libmv/libmv/multiview/projection.h b/intern/libmv/libmv/multiview/projection.h
index 3220bc2dbbc..8f304f31ec6 100644
--- a/intern/libmv/libmv/multiview/projection.h
+++ b/intern/libmv/libmv/multiview/projection.h
@@ -122,7 +122,7 @@ inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) {
inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) {
Vec3 hx;
- Project(P, X, x);
+ Project(P, X, &hx);
*x = hx.head<2>() / hx(2);
}
diff --git a/intern/libmv/libmv/numeric/numeric.cc b/intern/libmv/libmv/numeric/numeric.cc
index 9007663c8e2..3fc1e3b2bfd 100644
--- a/intern/libmv/libmv/numeric/numeric.cc
+++ b/intern/libmv/libmv/numeric/numeric.cc
@@ -109,7 +109,7 @@ void MeanAndVarianceAlongRows(const Mat &A,
}
void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked) {
- assert(left.rows() == left.rows());
+ assert(left.rows() == right.rows());
int n = left.rows();
int m1 = left.cols();
int m2 = right.cols();
diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h
index 20a4a29e5ba..a42dab8c7a2 100644
--- a/intern/libmv/libmv/numeric/numeric.h
+++ b/intern/libmv/libmv/numeric/numeric.h
@@ -148,7 +148,7 @@ using Eigen::Matrix;
// A = U * diag(s) * VT
//
template <typename TMat, typename TVec>
-inline void SVD(TMat *A, Vec *s, Mat *U, Mat *VT) {
+inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) {
assert(0);
}
diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
index 311b89b97cf..f8e80de7f8f 100644
--- a/intern/opensubdiv/CMakeLists.txt
+++ b/intern/opensubdiv/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SRC
opensubdiv_device_context_cuda.h
opensubdiv_device_context_opencl.h
opensubdiv_intern.h
+ opensubdiv_topology_refiner.h
)
macro(OPENSUBDIV_DEFINE_COMPONENT component)
@@ -69,6 +70,7 @@ add_definitions(-DGLEW_STATIC)
if(WIN32)
add_definitions(-DNOMINMAX)
+ add_definitions(-D_USE_MATH_DEFINES)
endif()
# TODO(sergey): Put CUEW back when CUDA is officially supported by OSD.
diff --git a/intern/opensubdiv/gpu_shader_opensubd_display.glsl b/intern/opensubdiv/gpu_shader_opensubd_display.glsl
index a17dcef81c7..5193d3a71dc 100644
--- a/intern/opensubdiv/gpu_shader_opensubd_display.glsl
+++ b/intern/opensubdiv/gpu_shader_opensubd_display.glsl
@@ -99,6 +99,7 @@ in block {
}
uniform samplerBuffer FVarDataBuffer;
+uniform isamplerBuffer FVarDataOffsetBuffer;
out block {
VertexData v;
@@ -208,6 +209,7 @@ struct LightSource {
float spotCutoff;
float spotExponent;
float spotCosCutoff;
+ float pad, pad2;
#endif
};
@@ -240,6 +242,7 @@ void main()
vec3 L_diffuse = vec3(0.0);
vec3 L_specular = vec3(0.0);
+#ifdef USE_LIGHTING
#ifndef USE_COLOR_MATERIAL
/* Assume NUM_SOLID_LIGHTS directional lights. */
for (int i = 0; i < NUM_SOLID_LIGHTS; i++) {
@@ -310,6 +313,9 @@ void main()
L_specular += light_specular * specular_bsdf * intensity;
}
#endif /* USE_COLOR_MATERIAL */
+#else /* USE_LIGHTING */
+ L_diffuse = vec3(1.0);
+#endif
/* Compute diffuse color. */
#ifdef USE_TEXTURE_2D
diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc
index 9b9f4baa39e..ab904953c70 100644
--- a/intern/opensubdiv/opensubdiv_capi.cc
+++ b/intern/opensubdiv/opensubdiv_capi.cc
@@ -67,8 +67,10 @@
#include <opensubdiv/osd/glPatchTable.h>
#include <opensubdiv/far/stencilTable.h>
+#include <opensubdiv/far/primvarRefiner.h>
#include "opensubdiv_intern.h"
+#include "opensubdiv_topology_refiner.h"
#include "MEM_guardedalloc.h"
@@ -142,11 +144,73 @@ typedef Mesh<GLVertexBuffer,
GLPatchTable> OsdGLSLComputeMesh;
#endif
+namespace {
+
+struct FVarVertex {
+ float u, v;
+ void Clear() {
+ u = v = 0.0f;
+ }
+ void AddWithWeight(FVarVertex const & src, float weight) {
+ u += weight * src.u;
+ v += weight * src.v;
+ }
+};
+
+static void interpolate_fvar_data(OpenSubdiv::Far::TopologyRefiner& refiner,
+ const std::vector<float> uvs,
+ std::vector<float> &fvar_data) {
+ /* TODO(sergey): Make it somehow more generic way. */
+ const int fvar_width = 2;
+ const int max_level = refiner.GetMaxLevel();
+ size_t fvar_data_offset = 0, values_offset = 0;
+ for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) {
+ const int num_values = refiner.GetLevel(0).GetNumFVarValues(0) * 2,
+ num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel),
+ num_values_total = refiner.GetNumFVarValuesTotal(channel);
+ if (num_values_total <= 0) {
+ continue;
+ }
+ OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner);
+ if (refiner.IsUniform()) {
+ /* For uniform we only keep the highest level of refinement. */
+ fvar_data.resize(fvar_data.size() + num_values_max * fvar_width);
+ std::vector<FVarVertex> buffer(num_values_total - num_values_max);
+ FVarVertex *src = &buffer[0];
+ memcpy(src, &uvs[values_offset], num_values * sizeof(float));
+ /* Defer the last level to treat separately with its alternate
+ * destination.
+ */
+ for (int level = 1; level < max_level; ++level) {
+ FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
+ primvar_refiner.InterpolateFaceVarying(level, src, dst, channel);
+ src = dst;
+ }
+ FVarVertex *dst = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]);
+ primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel);
+ fvar_data_offset += num_values_max * fvar_width;
+ } else {
+ /* For adaptive we keep all levels. */
+ fvar_data.resize(fvar_data.size() + num_values_total * fvar_width);
+ FVarVertex *src = reinterpret_cast<FVarVertex *>(&fvar_data[fvar_data_offset]);
+ memcpy(src, &uvs[values_offset], num_values * sizeof(float));
+ for (int level = 1; level <= max_level; ++level) {
+ FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
+ primvar_refiner.InterpolateFaceVarying(level, src, dst, channel);
+ src = dst;
+ }
+ fvar_data_offset += num_values_total * fvar_width;
+ }
+ values_offset += num_values;
+ }
+}
+
+} // namespace
+
struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
OpenSubdiv_TopologyRefinerDescr *topology_refiner,
int evaluator_type,
- int level,
- int /*subdivide_uvs*/)
+ int level)
{
using OpenSubdiv::Far::TopologyRefiner;
@@ -164,7 +228,7 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
const int num_varying_elements = 3;
GLMeshInterface *mesh = NULL;
- TopologyRefiner *refiner = (TopologyRefiner*)topology_refiner;
+ TopologyRefiner *refiner = topology_refiner->osd_refiner;
switch(evaluator_type) {
#define CHECK_EVALUATOR_TYPE(type, class) \
@@ -210,13 +274,23 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
(OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
gl_mesh->evaluator_type = evaluator_type;
gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh;
- gl_mesh->topology_refiner = (OpenSubdiv_TopologyRefinerDescr*)refiner;
+ gl_mesh->topology_refiner = topology_refiner;
+
+ if (refiner->GetNumFVarChannels() > 0) {
+ std::vector<float> fvar_data;
+ interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data);
+ openSubdiv_osdGLAllocFVar(topology_refiner, gl_mesh, &fvar_data[0]);
+ }
+ else {
+ gl_mesh->fvar_data = NULL;
+ }
return gl_mesh;
}
void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
{
+ openSubdiv_osdGLDestroyFVar(gl_mesh);
switch (gl_mesh->evaluator_type) {
#define CHECK_EVALUATOR_TYPE(type, class) \
case OPENSUBDIV_EVALUATOR_ ## type: \
@@ -249,6 +323,8 @@ void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
#undef CHECK_EVALUATOR_TYPE
}
+ /* NOTE: OSD refiner was owned by gl_mesh, no need to free it here. */
+ OBJECT_GUARDED_DELETE(gl_mesh->topology_refiner, OpenSubdiv_TopologyRefinerDescr);
OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
}
@@ -299,6 +375,9 @@ int openSubdiv_supportGPUDisplay(void)
return openSubdiv_gpu_legacy_support() &&
(GLEW_VERSION_3_2 ||
(GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) ||
- (GLEW_VERSION_3_0 && GLEW_EXT_geometry_shader4 && GLEW_ARB_uniform_buffer_object && (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object)));
+ (GLEW_VERSION_3_0 &&
+ GLEW_EXT_geometry_shader4 &&
+ GLEW_ARB_uniform_buffer_object &&
+ (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object)));
/* also ARB_explicit_attrib_location? */
}
diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
index b40505b197d..c3a194813e6 100644
--- a/intern/opensubdiv/opensubdiv_capi.h
+++ b/intern/opensubdiv/opensubdiv_capi.h
@@ -32,16 +32,19 @@ extern "C" {
// Types declaration.
struct OpenSubdiv_GLMesh;
+struct OpenSubdiv_GLMeshFVarData;
struct OpenSubdiv_TopologyRefinerDescr;
typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh;
#ifdef __cplusplus
struct OpenSubdiv_GLMeshDescr;
+
typedef struct OpenSubdiv_GLMesh {
int evaluator_type;
OpenSubdiv_GLMeshDescr *descriptor;
OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+ OpenSubdiv_GLMeshFVarData *fvar_data;
} OpenSubdiv_GLMesh;
#endif
@@ -66,8 +69,7 @@ enum {
OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
int evaluator_type,
- int level,
- int subdivide_uvs);
+ int level);
void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh);
unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(
@@ -138,6 +140,11 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
int start_patch,
int num_patches);
+void openSubdiv_osdGLAllocFVar(struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
+ OpenSubdiv_GLMesh *gl_mesh,
+ const float *fvar_data);
+void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh);
+
/* ** Utility functions ** */
int openSubdiv_supportGPUDisplay(void);
int openSubdiv_getAvailableEvaluators(void);
diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc
index 3fadde68d32..ea41a56768f 100644
--- a/intern/opensubdiv/opensubdiv_converter.cc
+++ b/intern/opensubdiv/opensubdiv_converter.cc
@@ -32,8 +32,12 @@
#include <opensubdiv/far/topologyRefinerFactory.h>
+#include "MEM_guardedalloc.h"
+
#include "opensubdiv_converter_capi.h"
#include "opensubdiv_intern.h"
+#include "opensubdiv_topology_refiner.h"
+
#include <stack>
@@ -49,6 +53,11 @@ inline void reverse_face_verts(int *face_verts, int num_verts)
face_verts[0] = last_vert;
}
+struct TopologyRefinerData {
+ const OpenSubdiv_Converter& conv;
+ std::vector<float> *uvs;
+};
+
} /* namespace */
#endif /* OPENSUBDIV_ORIENT_TOPOLOGY */
@@ -137,10 +146,11 @@ inline void check_oriented_vert_connectivity(const int num_vert_edges,
} /* namespace */
template <>
-inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopology(
+inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology(
TopologyRefiner& refiner,
- const OpenSubdiv_Converter& conv)
+ const TopologyRefinerData& cb_data)
{
+ const OpenSubdiv_Converter& conv = cb_data.conv;
/* Faces and face-verts */
const int num_faces = conv.get_num_faces(&conv);
setNumBaseFaces(refiner, num_faces);
@@ -168,10 +178,11 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::resizeComponentTopolog
}
template <>
-inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopology(
+inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology(
TopologyRefiner& refiner,
- const OpenSubdiv_Converter& conv)
+ const TopologyRefinerData &cb_data)
{
+ const OpenSubdiv_Converter& conv = cb_data.conv;
using Far::IndexArray;
/* Face relations. */
const int num_faces = conv.get_num_faces(&conv);
@@ -332,7 +343,6 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog
else {
/* Special handle of non-manifold vertex. */
for (int i = 0; i < num_vert_edges; ++i) {
- bool start_found = false;
edge_start = vert_edges[i];
IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start);
if (edge_faces.size() == 1) {
@@ -343,14 +353,10 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog
face_edges = getBaseFaceEdges(refiner, face_start);
face_vert_start = findInArray(face_verts, vert);
if (edge_start == face_edges[face_vert_start]) {
- start_found = true;
break;
}
}
}
- if (start_found) {
- break;
- }
/* Reset indices for sanity check below. */
face_start = edge_start = face_vert_start = -1;
}
@@ -431,10 +437,11 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog
};
template <>
-inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags(
+inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags(
TopologyRefiner& refiner,
- const OpenSubdiv_Converter& conv)
+ const TopologyRefinerData& cb_data)
{
+ const OpenSubdiv_Converter& conv = cb_data.conv;
typedef OpenSubdiv::Sdc::Crease Crease;
int num_edges = conv.get_num_edges(&conv);
@@ -481,14 +488,52 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTags(
}
template <>
-inline void TopologyRefinerFactory<OpenSubdiv_Converter>::reportInvalidTopology(
+inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology(
TopologyError /*errCode*/,
const char *msg,
- const OpenSubdiv_Converter& /*mesh*/)
+ const TopologyRefinerData& /*mesh*/)
{
printf("OpenSubdiv Error: %s\n", msg);
}
+template <>
+inline bool TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology(
+ TopologyRefiner& refiner,
+ const TopologyRefinerData& cb_data)
+{
+ const OpenSubdiv_Converter& conv = cb_data.conv;
+ const int num_layers = conv.get_num_uv_layers(&conv);
+ if (num_layers <= 0) {
+ /* No UV maps, we can skip any face-varying data. */
+ return true;
+ }
+ const int num_faces = getNumBaseFaces(refiner);
+ size_t uvs_offset = 0;
+ for (int layer = 0; layer < num_layers; ++layer) {
+ conv.precalc_uv_layer(&conv, layer);
+ const int num_uvs = conv.get_num_uvs(&conv);
+ /* Fill in UV coordinates. */
+ cb_data.uvs->resize(cb_data.uvs->size() + num_uvs * 2);
+ conv.get_uvs(&conv, &cb_data.uvs->at(uvs_offset));
+ uvs_offset += num_uvs * 2;
+ /* Fill in per-corner index of the UV. */
+ const int channel = createBaseFVarChannel(refiner, num_uvs);
+ for (int face = 0; face < num_faces; ++face) {
+ Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner,
+ face,
+ channel);
+ for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
+ const int uv_index = conv.get_face_corner_uv_index(&conv,
+ face,
+ corner);
+ dst_face_uvs[corner] = uv_index;
+ }
+ }
+ conv.finish_uv_layer(&conv);
+ }
+ return true;
+}
+
} /* namespace Far */
} /* namespace OPENSUBDIV_VERSION */
} /* namespace OpenSubdiv */
@@ -522,33 +567,43 @@ struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
Options options;
options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY);
options.SetCreasingMethod(Options::CREASE_UNIFORM);
- options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL);
+ if (converter->get_subdiv_uvs(converter)) {
+ options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_CORNERS_ONLY);
+ }
+ else {
+ options.SetFVarLinearInterpolation(Options::FVAR_LINEAR_ALL);
+ }
- TopologyRefinerFactory<OpenSubdiv_Converter>::Options
+ TopologyRefinerFactory<TopologyRefinerData>::Options
topology_options(scheme_type, options);
#ifdef OPENSUBDIV_VALIDATE_TOPOLOGY
topology_options.validateFullTopology = true;
#endif
+ OpenSubdiv_TopologyRefinerDescr *result = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerDescr);
+ TopologyRefinerData cb_data = {*converter, &result->uvs};
/* We don't use guarded allocation here so we can re-use the refiner
* for GL mesh creation directly.
*/
- return (struct OpenSubdiv_TopologyRefinerDescr*)
- TopologyRefinerFactory<OpenSubdiv_Converter>::Create(
- *converter,
+ result->osd_refiner =
+ TopologyRefinerFactory<TopologyRefinerData>::Create(
+ cb_data,
topology_options);
+
+ return result;
}
void openSubdiv_deleteTopologyRefinerDescr(
OpenSubdiv_TopologyRefinerDescr *topology_refiner)
{
- delete (OpenSubdiv::Far::TopologyRefiner *)topology_refiner;
+ delete topology_refiner->osd_refiner;
+ OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefinerDescr);
}
int openSubdiv_topologyRefinerGetSubdivLevel(
const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
{
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
return refiner->GetMaxLevel();
}
@@ -557,7 +612,7 @@ int openSubdiv_topologyRefinerGetNumVerts(
{
using OpenSubdiv::Far::TopologyLevel;
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
return base_level.GetNumVertices();
}
@@ -567,7 +622,7 @@ int openSubdiv_topologyRefinerGetNumEdges(
{
using OpenSubdiv::Far::TopologyLevel;
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
return base_level.GetNumEdges();
}
@@ -577,7 +632,7 @@ int openSubdiv_topologyRefinerGetNumFaces(
{
using OpenSubdiv::Far::TopologyLevel;
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
return base_level.GetNumFaces();
}
@@ -588,7 +643,7 @@ int openSubdiv_topologyRefinerGetNumFaceVerts(
{
using OpenSubdiv::Far::TopologyLevel;
using OpenSubdiv::Far::TopologyRefiner;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
return base_level.GetFaceVertices(face).size();
}
@@ -597,10 +652,11 @@ int openSubdiv_topologyRefnerCompareConverter(
const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
OpenSubdiv_Converter *converter)
{
+ typedef OpenSubdiv::Sdc::Options Options;
using OpenSubdiv::Far::ConstIndexArray;
using OpenSubdiv::Far::TopologyRefiner;
using OpenSubdiv::Far::TopologyLevel;
- const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+ const TopologyRefiner *refiner = topology_refiner->osd_refiner;
const TopologyLevel &base_level = refiner->GetLevel(0);
const int num_verts = base_level.GetNumVertices();
const int num_edges = base_level.GetNumEdges();
@@ -611,6 +667,12 @@ int openSubdiv_topologyRefnerCompareConverter(
if (scheme_type != refiner->GetSchemeType()) {
return false;
}
+ const Options options = refiner->GetSchemeOptions();
+ Options::FVarLinearInterpolation interp = options.GetFVarLinearInterpolation();
+ const bool subdiv_uvs = (interp != Options::FVAR_LINEAR_ALL);
+ if (converter->get_subdiv_uvs(converter) != subdiv_uvs) {
+ return false;
+ }
if (converter->get_num_verts(converter) != num_verts ||
converter->get_num_edges(converter) != num_edges ||
converter->get_num_faces(converter) != num_faces)
diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h
index 1f09fa074d8..6eda6ae5d8a 100644
--- a/intern/opensubdiv/opensubdiv_converter_capi.h
+++ b/intern/opensubdiv/opensubdiv_converter_capi.h
@@ -47,6 +47,8 @@ typedef struct OpenSubdiv_Converter {
OpenSubdiv_SchemeType (*get_type)(const OpenSubdiv_Converter *converter);
+ bool (*get_subdiv_uvs)(const OpenSubdiv_Converter *converter);
+
int (*get_num_faces)(const OpenSubdiv_Converter *converter);
int (*get_num_edges)(const OpenSubdiv_Converter *converter);
int (*get_num_verts)(const OpenSubdiv_Converter *converter);
@@ -83,6 +85,20 @@ typedef struct OpenSubdiv_Converter {
int vert,
int *vert_faces);
+ /* Face-varying data. */
+
+ int (*get_num_uv_layers)(const OpenSubdiv_Converter *converter);
+
+ void (*precalc_uv_layer)(const OpenSubdiv_Converter *converter, int layer);
+ void (*finish_uv_layer)(const OpenSubdiv_Converter *converter);
+
+ int (*get_num_uvs)(const OpenSubdiv_Converter *converter);
+ void (*get_uvs)(const OpenSubdiv_Converter *converter, float *uvs);
+
+ int (*get_face_corner_uv_index)(const OpenSubdiv_Converter *converter,
+ int face,
+ int corner);
+
void (*free_user_data)(const OpenSubdiv_Converter *converter);
void *user_data;
} OpenSubdiv_Converter;
diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc
index 698fdfee00f..0cf6fcfef43 100644
--- a/intern/opensubdiv/opensubdiv_gpu_capi.cc
+++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc
@@ -42,11 +42,29 @@
#include <opensubdiv/osd/cpuGLVertexBuffer.h>
#include <opensubdiv/osd/cpuEvaluator.h>
+#include "MEM_guardedalloc.h"
+
+#include "opensubdiv_capi.h"
+#include "opensubdiv_topology_refiner.h"
+
using OpenSubdiv::Osd::GLMeshInterface;
extern "C" char datatoc_gpu_shader_opensubd_display_glsl[];
+/* TODO(sergey): This is bit of bad level calls :S */
+extern "C" {
+void copy_m3_m3(float m1[3][3], float m2[3][3]);
+void copy_m3_m4(float m1[3][3], float m2[4][4]);
+void adjoint_m3_m3(float m1[3][3], float m[3][3]);
+float determinant_m3_array(float m[3][3]);
+bool invert_m3_m3(float m1[3][3], float m2[3][3]);
+bool invert_m3(float m[3][3]);
+void transpose_m3(float mat[3][3]);
+}
+
#define MAX_LIGHTS 8
+#define SUPPORT_COLOR_MATERIAL
+
typedef struct Light {
float position[4];
float ambient[4];
@@ -60,6 +78,7 @@ typedef struct Light {
float spot_cutoff;
float spot_exponent;
float spot_cos_cutoff;
+ float pad, pad2;
#endif
} Light;
@@ -75,114 +94,116 @@ typedef struct Transform {
} Transform;
static bool g_use_osd_glsl = false;
-static int g_active_uv_index = -1;
+static int g_active_uv_index = 0;
static GLuint g_flat_fill_solid_program = 0;
static GLuint g_flat_fill_texture2d_program = 0;
static GLuint g_smooth_fill_solid_program = 0;
static GLuint g_smooth_fill_texture2d_program = 0;
+
+static GLuint g_flat_fill_solid_shadeless_program = 0;
+static GLuint g_flat_fill_texture2d_shadeless_program = 0;
+static GLuint g_smooth_fill_solid_shadeless_program = 0;
+static GLuint g_smooth_fill_texture2d_shadeless_program = 0;
+
static GLuint g_wireframe_program = 0;
static GLuint g_lighting_ub = 0;
static Lighting g_lighting_data;
static Transform g_transform;
-/* TODO(sergey): This is actually duplicated code from BLI. */
-namespace {
-void copy_m3_m3(float m1[3][3], float m2[3][3])
-{
- /* destination comes first: */
- memcpy(&m1[0], &m2[0], 9 * sizeof(float));
-}
-
-void copy_m3_m4(float m1[3][3], float m2[4][4])
-{
- m1[0][0] = m2[0][0];
- m1[0][1] = m2[0][1];
- m1[0][2] = m2[0][2];
-
- m1[1][0] = m2[1][0];
- m1[1][1] = m2[1][1];
- m1[1][2] = m2[1][2];
-
- m1[2][0] = m2[2][0];
- m1[2][1] = m2[2][1];
- m1[2][2] = m2[2][2];
-}
-
-void adjoint_m3_m3(float m1[3][3], float m[3][3])
-{
- m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1];
- m1[0][1] = -m[0][1] * m[2][2] + m[0][2] * m[2][1];
- m1[0][2] = m[0][1] * m[1][2] - m[0][2] * m[1][1];
-
- m1[1][0] = -m[1][0] * m[2][2] + m[1][2] * m[2][0];
- m1[1][1] = m[0][0] * m[2][2] - m[0][2] * m[2][0];
- m1[1][2] = -m[0][0] * m[1][2] + m[0][2] * m[1][0];
-
- m1[2][0] = m[1][0] * m[2][1] - m[1][1] * m[2][0];
- m1[2][1] = -m[0][0] * m[2][1] + m[0][1] * m[2][0];
- m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0];
-}
-
-float determinant_m3_array(float m[3][3])
+struct OpenSubdiv_GLMeshFVarData
{
- return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
- m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
- m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
-}
-
-bool invert_m3_m3(float m1[3][3], float m2[3][3])
-{
- float det;
- int a, b;
- bool success;
-
- /* calc adjoint */
- adjoint_m3_m3(m1, m2);
+ OpenSubdiv_GLMeshFVarData() :
+ texture_buffer(0) {
+ }
- /* then determinant old matrix! */
- det = determinant_m3_array(m2);
+ ~OpenSubdiv_GLMeshFVarData()
+ {
+ Release();
+ }
- success = (det != 0.0f);
+ void Release()
+ {
+ if (texture_buffer) {
+ glDeleteTextures(1, &texture_buffer);
+ }
+ if (offset_buffer) {
+ glDeleteTextures(1, &offset_buffer);
+ }
+ texture_buffer = 0;
+ offset_buffer = 0;
+ fvar_width = 0;
+ channel_offsets.clear();
+ }
- if (det != 0.0f) {
- det = 1.0f / det;
- for (a = 0; a < 3; a++) {
- for (b = 0; b < 3; b++) {
- m1[a][b] *= det;
+ void Create(const OpenSubdiv::Far::TopologyRefiner *refiner,
+ const OpenSubdiv::Far::PatchTable *patch_table,
+ int fvar_width,
+ const float *fvar_src_data)
+ {
+ Release();
+
+ this->fvar_width = fvar_width;
+
+ /* Expand fvar data to per-patch array */
+ const int max_level = refiner->GetMaxLevel();
+ const int num_channels = patch_table->GetNumFVarChannels();
+ std::vector<float> data;
+ int fvar_data_offset = 0;
+ channel_offsets.resize(num_channels);
+ for (int channel = 0; channel < num_channels; ++channel) {
+ OpenSubdiv::Far::ConstIndexArray indices =
+ patch_table->GetFVarValues(channel);
+
+ channel_offsets[channel] = data.size();
+ data.reserve(data.size() + indices.size() * fvar_width);
+
+ for (int fvert = 0; fvert < (int)indices.size(); ++fvert) {
+ int index = indices[fvert] * fvar_width;
+ for (int i = 0; i < fvar_width; ++i) {
+ data.push_back(fvar_src_data[fvar_data_offset + index++]);
+ }
+ }
+ if (refiner->IsUniform()) {
+ const int num_values_max = refiner->GetLevel(max_level).GetNumFVarValues(channel);
+ fvar_data_offset += num_values_max * fvar_width;
+ } else {
+ const int num_values_total = refiner->GetNumFVarValuesTotal(channel);
+ fvar_data_offset += num_values_total * fvar_width;
}
}
- }
- return success;
-}
+ GLuint buffer;
+ glGenBuffers(1, &buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ glBufferData(GL_ARRAY_BUFFER, data.size()*sizeof(float),
+ &data[0], GL_STATIC_DRAW);
-bool invert_m3(float m[3][3])
-{
- float tmp[3][3];
- bool success;
+ glGenTextures(1, &texture_buffer);
+ glBindTexture(GL_TEXTURE_BUFFER, texture_buffer);
+ glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer);
- success = invert_m3_m3(tmp, m);
- copy_m3_m3(m, tmp);
+ glDeleteBuffers(1, &buffer);
- return success;
-}
+ glGenBuffers(1, &buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ glBufferData(GL_ARRAY_BUFFER, channel_offsets.size()*sizeof(int),
+ &channel_offsets[0], GL_STATIC_DRAW);
-void transpose_m3(float mat[3][3])
-{
- float t;
-
- t = mat[0][1];
- mat[0][1] = mat[1][0];
- mat[1][0] = t;
- t = mat[0][2];
- mat[0][2] = mat[2][0];
- mat[2][0] = t;
- t = mat[1][2];
- mat[1][2] = mat[2][1];
- mat[2][1] = t;
-}
+ glGenTextures(1, &offset_buffer);
+ glBindTexture(GL_TEXTURE_BUFFER, offset_buffer);
+ glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer);
+ glBindTexture(GL_TEXTURE_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+ GLuint texture_buffer;
+ GLuint offset_buffer;
+ std::vector<int> channel_offsets;
+ int fvar_width;
+};
+
+namespace {
GLuint compileShader(GLenum shaderType,
const char *section,
@@ -196,11 +217,14 @@ GLuint compileShader(GLenum shaderType,
version,
define,
sdefine,
+#ifdef SUPPORT_COLOR_MATERIAL
+ "#define SUPPORT_COLOR_MATERIAL\n",
+#endif
datatoc_gpu_shader_opensubd_display_glsl
};
GLuint shader = glCreateShader(shaderType);
- glShaderSource(shader, 4, sources, NULL);
+ glShaderSource(shader, 5, sources, NULL);
glCompileShader(shader);
GLint status;
@@ -295,14 +319,17 @@ GLuint linkProgram(const char *version, const char *define)
0); /* GL_TEXTURE0 */
glProgramUniform1i(program,
+ glGetUniformLocation(program, "FVarDataOffsetBuffer"),
+ 30); /* GL_TEXTURE30 */
+
+ glProgramUniform1i(program,
glGetUniformLocation(program, "FVarDataBuffer"),
31); /* GL_TEXTURE31 */
return program;
}
-void bindProgram(GLMeshInterface * /*mesh*/,
- int program)
+void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program)
{
glUseProgram(program);
@@ -346,23 +373,34 @@ void bindProgram(GLMeshInterface * /*mesh*/,
glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
}
- /* TODO(sergey): Bring face varying back. */
-#if 0
/* Face-vertex data */
- if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
- glActiveTexture(GL_TEXTURE31);
- glBindTexture(GL_TEXTURE_BUFFER,
- mesh->GetDrawContext()->GetFvarDataTextureBuffer());
- glActiveTexture(GL_TEXTURE0);
- }
-#endif
+ if (gl_mesh->fvar_data != NULL) {
+ if (gl_mesh->fvar_data->texture_buffer) {
+ glActiveTexture(GL_TEXTURE31);
+ glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->texture_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
- /* TODO(sergey): Bring face varying back. */
- glUniform1i(glGetUniformLocation(program, "osd_fvar_count"),
- 0/* * mesh->GetFVarCount()*/);
+ if (gl_mesh->fvar_data->offset_buffer) {
+ glActiveTexture(GL_TEXTURE30);
+ glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->offset_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
- glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"),
- g_active_uv_index * 2);
+ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"),
+ gl_mesh->fvar_data->fvar_width);
+ if (gl_mesh->fvar_data->channel_offsets.size() > 0 &&
+ g_active_uv_index >= 0)
+ {
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"),
+ gl_mesh->fvar_data->channel_offsets[g_active_uv_index]);
+ } else {
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
+ }
+ } else {
+ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0);
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
+ }
}
} /* namespace */
@@ -390,11 +428,51 @@ bool openSubdiv_osdGLDisplayInit(void)
/* minimum supported for OpenSubdiv */
}
- g_flat_fill_solid_program = linkProgram(version, "#define FLAT_SHADING\n");
- g_flat_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define FLAT_SHADING\n");
- g_smooth_fill_solid_program = linkProgram(version, "#define SMOOTH_SHADING\n");
- g_smooth_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n");
- g_wireframe_program = linkProgram(version, "#define WIREFRAME\n");
+ g_flat_fill_solid_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define FLAT_SHADING\n");
+ g_flat_fill_texture2d_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define FLAT_SHADING\n");
+ g_smooth_fill_solid_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define SMOOTH_SHADING\n");
+ g_smooth_fill_texture2d_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_LIGHTING\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define SMOOTH_SHADING\n");
+
+ g_flat_fill_solid_shadeless_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define FLAT_SHADING\n");
+ g_flat_fill_texture2d_shadeless_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define FLAT_SHADING\n");
+ g_smooth_fill_solid_shadeless_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define SMOOTH_SHADING\n");
+ g_smooth_fill_texture2d_shadeless_program = linkProgram(
+ version,
+ "#define USE_COLOR_MATERIAL\n"
+ "#define USE_TEXTURE_2D\n"
+ "#define SMOOTH_SHADING\n");
+
+ g_wireframe_program = linkProgram(
+ version,
+ "#define WIREFRAME\n");
glGenBuffers(1, &g_lighting_ub);
glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
@@ -416,28 +494,31 @@ void openSubdiv_osdGLDisplayDeinit(void)
if (g_lighting_ub != 0) {
glDeleteBuffers(1, &g_lighting_ub);
}
- if (g_flat_fill_solid_program) {
- glDeleteProgram(g_flat_fill_solid_program);
- }
- if (g_flat_fill_texture2d_program) {
- glDeleteProgram(g_flat_fill_texture2d_program);
- }
- if (g_smooth_fill_solid_program) {
- glDeleteProgram(g_flat_fill_solid_program);
- }
- if (g_smooth_fill_texture2d_program) {
- glDeleteProgram(g_smooth_fill_texture2d_program);
- }
- if (g_wireframe_program) {
- glDeleteProgram(g_wireframe_program);
- }
+#define SAFE_DELETE_PROGRAM(program) \
+ do { \
+ if (program) { \
+ glDeleteProgram(program); \
+ } \
+ } while (false)
+
+ SAFE_DELETE_PROGRAM(g_flat_fill_solid_program);
+ SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program);
+ SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program);
+ SAFE_DELETE_PROGRAM(g_wireframe_program);
+
+#undef SAFE_DELETE_PROGRAM
}
void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
int active_uv_index)
{
- g_use_osd_glsl = use_osd_glsl != 0;
g_active_uv_index = active_uv_index;
+ g_use_osd_glsl = (use_osd_glsl != 0);
/* Update transformation matrices. */
glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix);
@@ -494,7 +575,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
}
}
-static GLuint prepare_patchDraw(GLMeshInterface *mesh,
+static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh,
bool fill_quads)
{
GLint program = 0;
@@ -509,51 +590,74 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh,
glUniform1i(location, model == GL_FLAT);
}
- /* TODO(sergey): Bring this back. */
-#if 0
/* Face-vertex data */
- if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
- glActiveTexture(GL_TEXTURE31);
- glBindTexture(GL_TEXTURE_BUFFER,
- mesh->GetDrawContext()->GetFvarDataTextureBuffer());
- glActiveTexture(GL_TEXTURE0);
+ if (gl_mesh->fvar_data != NULL) {
+ if (gl_mesh->fvar_data->texture_buffer) {
+ glActiveTexture(GL_TEXTURE31);
+ glBindTexture(GL_TEXTURE_BUFFER,
+ gl_mesh->fvar_data->texture_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
+
+ if (gl_mesh->fvar_data->offset_buffer) {
+ glActiveTexture(GL_TEXTURE30);
+ glBindTexture(GL_TEXTURE_BUFFER,
+ gl_mesh->fvar_data->offset_buffer);
+ glActiveTexture(GL_TEXTURE0);
+ }
GLint location = glGetUniformLocation(program, "osd_fvar_count");
if (location != -1) {
- glUniform1i(location, mesh->GetFVarCount());
+ glUniform1i(location, gl_mesh->fvar_data->fvar_width);
}
location = glGetUniformLocation(program, "osd_active_uv_offset");
if (location != -1) {
- glUniform1i(location,
- g_active_uv_index * 2);
+ if (gl_mesh->fvar_data->channel_offsets.size() > 0 &&
+ g_active_uv_index >= 0)
+ {
+ glUniform1i(location,
+ gl_mesh->fvar_data->channel_offsets[g_active_uv_index]);
+ } else {
+ glUniform1i(location, 0);
+ }
}
+ } else {
+ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0);
+ glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
}
-#endif
-
}
return program;
}
if (fill_quads) {
int model;
- GLboolean use_texture_2d;
+ GLboolean use_texture_2d, use_lighting;
glGetIntegerv(GL_SHADE_MODEL, &model);
glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d);
+ glGetBooleanv(GL_LIGHTING, &use_lighting);
if (model == GL_FLAT) {
if (use_texture_2d) {
- program = g_flat_fill_texture2d_program;
+ program = use_lighting
+ ? g_flat_fill_texture2d_program
+ : g_flat_fill_texture2d_shadeless_program;
}
else {
- program = g_flat_fill_solid_program;
+ program = use_lighting
+ ? g_flat_fill_solid_program
+ : g_flat_fill_solid_shadeless_program;
}
}
else {
if (use_texture_2d) {
- program = g_smooth_fill_texture2d_program;
+ program = use_lighting
+ ? g_smooth_fill_texture2d_program
+ : g_smooth_fill_texture2d_shadeless_program;
}
else {
- program = g_smooth_fill_solid_program;
+ program = use_lighting
+ ? g_smooth_fill_solid_program
+ : g_smooth_fill_solid_shadeless_program;
}
}
}
@@ -562,7 +666,7 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh,
program = g_wireframe_program;
}
- bindProgram(mesh, program);
+ bindProgram(gl_mesh, program);
return program;
}
@@ -623,7 +727,7 @@ static void draw_partition_patches_range(GLMeshInterface *mesh,
const int num_draw_patches = std::min(num_remained_patches,
num_block_patches - start_draw_patch);
perform_drawElements(program,
- i,
+ i + start_draw_patch,
num_draw_patches * num_control_verts,
patch.GetIndexBase() + start_draw_patch * num_control_verts);
num_remained_patches -= num_draw_patches;
@@ -669,7 +773,7 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
}
/* Setup GLSL/OpenGL to draw patches in current context. */
- GLuint program = prepare_patchDraw(mesh, fill_quads != 0);
+ GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0);
if (start_patch != -1) {
draw_partition_patches_range(mesh,
@@ -684,3 +788,23 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
/* Finish patch drawing by restoring all changes to the OpenGL context. */
finish_patchDraw(fill_quads != 0);
}
+
+void openSubdiv_osdGLAllocFVar(OpenSubdiv_TopologyRefinerDescr *topology_refiner,
+ OpenSubdiv_GLMesh *gl_mesh,
+ const float *fvar_data)
+{
+ GLMeshInterface *mesh =
+ (GLMeshInterface *)(gl_mesh->descriptor);
+ gl_mesh->fvar_data = OBJECT_GUARDED_NEW(OpenSubdiv_GLMeshFVarData);
+ gl_mesh->fvar_data->Create(topology_refiner->osd_refiner,
+ mesh->GetFarPatchTable(),
+ 2,
+ fvar_data);
+}
+
+void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh)
+{
+ if (gl_mesh->fvar_data != NULL) {
+ OBJECT_GUARDED_DELETE(gl_mesh->fvar_data, OpenSubdiv_GLMeshFVarData);
+ }
+}
diff --git a/intern/opensubdiv/opensubdiv_topology_refiner.h b/intern/opensubdiv/opensubdiv_topology_refiner.h
new file mode 100644
index 00000000000..b00f6a54201
--- /dev/null
+++ b/intern/opensubdiv/opensubdiv_topology_refiner.h
@@ -0,0 +1,41 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2016 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OPENSUBDIV_TOPOLOGY_REFINER_H__
+#define __OPENSUBDIV_TOPOLOGY_REFINER_H__
+
+#include <opensubdiv/far/topologyRefiner.h>
+
+typedef struct OpenSubdiv_TopologyRefinerDescr {
+ OpenSubdiv::Far::TopologyRefiner *osd_refiner;
+
+ /* TODO(sergey): For now only, need to find better place
+ * after revisiting whole OSD drawing pipeline and Blender
+ * integration.
+ */
+ std::vector<float> uvs;
+} OpenSubdiv_TopologyRefinerDescr;
+
+#endif /* __OPENSUBDIV_TOPOLOGY_REFINER_H__ */
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index dd6b79f6686..07fc9f0c338 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -329,16 +329,21 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"available with",
"brown fox",
"can't save image while rendering",
+ "constructive modifier",
+ "edge data",
"expected a timeline/animation area to be active",
"expected a view3d region",
"expected a view3d region & editcurve",
"expected a view3d region & editmesh",
+ "face data",
"image file not found",
"image format is read-only",
"image path can't be written to",
"in memory to enable editing!",
"jumps over",
"left",
+ "multi-res modifier",
+ "non-triangle face",
"right",
"the lazy dog",
"unable to load movie clip",
@@ -351,6 +356,7 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"unsupported format",
"unsupported image format",
"unsupported movie clip format",
+ "vertex data",
"verts only",
"virtual parents",
}
diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
index 98a117e95a6..ba782160edd 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -565,7 +565,9 @@ class SpellChecker:
"ui",
"unix",
"vbo", "vbos",
+ "wxyz",
"ycc", "ycca",
+ "yrgb",
"yuv", "yuva",
# Blender acronyms
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py
index 021a8bbb530..0cc6462e8d1 100644
--- a/release/scripts/modules/bpy_extras/anim_utils.py
+++ b/release/scripts/modules/bpy_extras/anim_utils.py
@@ -155,6 +155,11 @@ def bake_action(frame_start,
atd = obj.animation_data_create()
if action is None:
action = bpy.data.actions.new("Action")
+
+ # Leave tweak mode before trying to modify the action (T48397)
+ if atd.use_tweak_mode:
+ atd.use_tweak_mode = False
+
atd.action = action
# -------------------------------------------------------------------------
diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
index a120e2b2461..3b095c883a3 100644
--- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py
+++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
@@ -285,8 +285,7 @@ def lightmap_uvpack(meshes,
for face_sel in face_groups:
print("\nStarting unwrap")
- if len(face_sel) < 4:
- print("\tWarning, less then 4 faces, skipping")
+ if not face_sel:
continue
pretty_faces = [prettyface(f) for f in face_sel if f.loop_total >= 4]
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index af8431ba1dc..33af812b6c4 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -125,7 +125,7 @@ class DATA_PT_shape_curve(CurveButtonsPanel, Panel):
col.prop(curve, "use_fill_deform")
if is_curve:
- col.label(text="Path / Curve-Deform:")
+ col.label(text="Path/Curve-Deform:")
sub = col.column()
subsub = sub.row()
subsub.prop(curve, "use_radius")
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 7863c075344..c6bb6ccf05f 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -151,21 +151,16 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
col.label(text="Operation:")
col.prop(md, "operation", text="")
+ row = layout.row()
+ row.label("Solver:")
+ row.prop(md, "solver", expand=True)
col = split.column()
col.label(text="Object:")
col.prop(md, "object", text="")
- """
- layout.prop(md, "use_bmesh")
- if md.use_bmesh:
- box = layout.box()
- box.label("BMesh Options:")
- box.prop(md, "use_bmesh_separate")
- box.prop(md, "use_bmesh_dissolve")
- box.prop(md, "use_bmesh_connect_regions")
- box.prop(md, "threshold")
- """
+ if md.solver == 'BMESH':
+ layout.prop(md, "double_threshold")
def BUILD(self, layout, ob, md):
split = layout.split()
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index 8bb3cf2814c..58bb956f653 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -950,7 +950,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
- bl_label = "Proxy / Timecode"
+ bl_label = "Proxy/Timecode"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index ab95ea7f4a4..9a28776ef10 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -310,19 +310,36 @@ class INFO_MT_help(Menu):
def draw(self, context):
layout = self.layout
- layout.operator("wm.url_open", text="Manual", icon='HELP').url = "https://www.blender.org/manual"
- layout.operator("wm.url_open", text="Release Log", icon='URL').url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2]
+ layout.operator(
+ "wm.url_open", text="Manual", icon='HELP',
+ ).url = "https://www.blender.org/manual"
+ layout.operator(
+ "wm.url_open", text="Release Log", icon='URL',
+ ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2]
layout.separator()
- layout.operator("wm.url_open", text="Blender Website", icon='URL').url = "https://www.blender.org"
- layout.operator("wm.url_open", text="Blender Store", icon='URL').url = "https://store.blender.org"
- layout.operator("wm.url_open", text="Developer Community", icon='URL').url = "https://www.blender.org/get-involved/"
- layout.operator("wm.url_open", text="User Community", icon='URL').url = "https://www.blender.org/support/user-community"
+ layout.operator(
+ "wm.url_open", text="Blender Website", icon='URL',
+ ).url = "https://www.blender.org"
+ layout.operator(
+ "wm.url_open", text="Blender Store", icon='URL',
+ ).url = "https://store.blender.org"
+ layout.operator(
+ "wm.url_open", text="Developer Community", icon='URL',
+ ).url = "https://www.blender.org/get-involved/"
+ layout.operator(
+ "wm.url_open", text="User Community", icon='URL',
+ ).url = "https://www.blender.org/support/user-community"
layout.separator()
- layout.operator("wm.url_open", text="Report a Bug", icon='URL').url = "https://developer.blender.org/maniphest/task/create/?project=2&type=Bug"
+ layout.operator(
+ "wm.url_open", text="Report a Bug", icon='URL',
+ ).url = "https://developer.blender.org/maniphest/task/edit/form/1"
layout.separator()
- layout.operator("wm.url_open", text="Python API Reference", icon='URL').url = bpy.types.WM_OT_doc_view._prefix
+ layout.operator(
+ "wm.url_open", text="Python API Reference", icon='URL',
+ ).url = bpy.types.WM_OT_doc_view._prefix
+
layout.operator("wm.operator_cheat_sheet", icon='TEXT')
layout.operator("wm.sysinfo", icon='TEXT')
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 539ee7a6af4..4d1b9104344 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -972,7 +972,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel):
class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel):
- bl_label = "Proxy / Timecode"
+ bl_label = "Proxy/Timecode"
@classmethod
def poll(cls, context):
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index dc46aed08c0..1512f4f4600 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -489,7 +489,7 @@ class USERPREF_PT_system(Panel):
col.separator()
- col.label(text="Sequencer / Clip Editor:")
+ col.label(text="Sequencer/Clip Editor:")
# currently disabled in the code
# col.prop(system, "prefetch_frames")
col.prop(system, "memory_cache_limit")
@@ -1416,7 +1416,7 @@ class USERPREF_PT_addons(Panel):
split.operator("wm.url_open", text="Documentation", icon='HELP').url = info["wiki_url"]
split.operator("wm.url_open", text="Report a Bug", icon='URL').url = info.get(
"tracker_url",
- "http://developer.blender.org/maniphest/task/create/?project=3&type=Bug")
+ "https://developer.blender.org/maniphest/task/edit/form/2")
if user_addon:
split.operator("wm.addon_remove", text="Remove", icon='CANCEL').module = mod.__name__
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 09e3bf38333..fdf0996ac1e 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -367,6 +367,7 @@ class VIEW3D_MT_snap(Menu):
layout.operator("view3d.snap_selected_to_grid", text="Selection to Grid")
layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor").use_offset = False
layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Offset)").use_offset = True
+ layout.operator("view3d.snap_selected_to_active", text="Selection to Active")
layout.separator()
@@ -2471,6 +2472,7 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.operator("mesh.edge_face_add")
layout.operator("mesh.subdivide")
+ layout.operator("mesh.subdivide_edgering")
layout.operator("mesh.unsubdivide")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index ca1ab4c37dd..e9f4d715ec2 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -570,6 +570,7 @@ class VIEW3D_PT_tools_curveedit_options_stroke(View3DPanel, Panel):
if cps.curve_type == 'BEZIER':
col.label("Bezier Options:")
col.prop(cps, "error_threshold")
+ col.prop(cps, "fit_method")
col.prop(cps, "use_corners_detect")
col = layout.column()
@@ -1607,7 +1608,7 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel):
class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel):
bl_category = "Tools"
- bl_label = "Symmetry / Lock"
+ bl_label = "Symmetry/Lock"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index dfebaecb96e..44a1d08f1fd 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -370,12 +370,10 @@ static void blf_font_draw_buffer_ex(
fbuf[3] = 1.0f;
}
else {
- float alphatest;
fbuf[0] = (b_col_float[0] * a) + (fbuf[0] * (1.0f - a));
fbuf[1] = (b_col_float[1] * a) + (fbuf[1] * (1.0f - a));
fbuf[2] = (b_col_float[2] * a) + (fbuf[2] * (1.0f - a));
- fbuf[3] = (alphatest = (fbuf[3] + a)) < 1.0f ?
- alphatest : 1.0f;
+ fbuf[3] = MIN2(fbuf[3] + a, 1.0f); /* clamp to 1.0 */
}
}
}
@@ -407,12 +405,10 @@ static void blf_font_draw_buffer_ex(
cbuf[3] = 255;
}
else {
- int alphatest;
cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a)));
cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a)));
cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a)));
- cbuf[3] = (unsigned char)(((alphatest = ((int)cbuf[3] + (int)(a * 255))) < 255) ?
- alphatest : 255);
+ cbuf[3] = (unsigned char)MIN2((int)cbuf[3] + (int)(a * 255), 255); /* clamp to 255 */
}
}
}
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 5874f95502b..6527ba7f94f 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -63,7 +63,7 @@ struct bAction *BKE_action_copy(struct Main *bmain, struct bAction *src);
/* Deallocate all of the Action's data, but not the Action itself */
void BKE_action_free(struct bAction *act);
-void BKE_action_make_local(struct Main *bmain, struct bAction *act);
+void BKE_action_make_local(struct Main *bmain, struct bAction *act, const bool lib_local);
/* Action API ----------------- */
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 326c335338f..c2323100205 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -76,7 +76,7 @@ struct bArmature *BKE_armature_from_object(struct Object *ob);
int BKE_armature_bonelist_count(struct ListBase *lb);
void BKE_armature_bonelist_free(struct ListBase *lb);
void BKE_armature_free(struct bArmature *arm);
-void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm);
+void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm, const bool lib_local);
struct bArmature *BKE_armature_copy(struct Main *bmain, struct bArmature *arm);
/* Bounding box. */
@@ -95,6 +95,7 @@ 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_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);
diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset_engine.h
index 4a5ed587c3f..db6769e1c74 100644
--- a/source/blender/blenkernel/BKE_asset.h
+++ b/source/blender/blenkernel/BKE_asset_engine.h
@@ -25,12 +25,12 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file BKE_asset.h
+/** \file BKE_asset_engine.h
* \ingroup bke
*/
-#ifndef __BKE_ASSET_H__
-#define __BKE_ASSET_H__
+#ifndef __BKE_ASSET_ENGINE_H__
+#define __BKE_ASSET_ENGINE_H__
#ifdef __cplusplus
extern "C" {
@@ -234,12 +234,13 @@ void BKE_filedir_entryarr_clear(struct FileDirEntryArr *array);
ASSETUUID_SUB_COMPARE(_uuida, _uuidb, uuid_variant) && \
ASSETUUID_SUB_COMPARE(_uuida, _uuidb, uuid_revision))
-/* GHash helpers */
+/* Various helpers */
unsigned int BKE_asset_uuid_hash(const void *key);
bool BKE_asset_uuid_cmp(const void *a, const void *b);
+void BKE_asset_uuid_print(const struct AssetUUID *uuid);
#ifdef __cplusplus
}
#endif
-#endif /* __BKE_ASSET_H__ */
+#endif /* __BKE_ASSET_ENGINE_H__ */
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index c7116bf2ef6..8bd4bdf89e1 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -45,7 +45,7 @@ void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode);
struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode);
struct Brush *BKE_brush_copy(struct Main *bmain, struct Brush *brush);
-void BKE_brush_make_local(struct Main *bmain, struct Brush *brush);
+void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local);
void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index 97f4b30894b..31a732cf7e5 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -53,7 +53,7 @@ struct GPUFXSettings;
void BKE_camera_init(struct Camera *cam);
void *BKE_camera_add(struct Main *bmain, const char *name);
struct Camera *BKE_camera_copy(struct Main *bmain, struct Camera *cam);
-void BKE_camera_make_local(struct Main *bmain, struct Camera *cam);
+void BKE_camera_make_local(struct Main *bmain, struct Camera *cam, const bool lib_local);
void BKE_camera_free(struct Camera *ca);
/* Camera Usage */
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 89dbe246910..5558786d254 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -71,7 +71,7 @@ void BKE_curve_editfont_free(struct Curve *cu);
void BKE_curve_init(struct Curve *cu);
struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type);
struct Curve *BKE_curve_copy(struct Main *bmain, struct Curve *cu);
-void BKE_curve_make_local(struct Main *bmain, struct Curve *cu);
+void BKE_curve_make_local(struct Main *bmain, struct Curve *cu, const bool lib_local);
short BKE_curve_type_get(struct Curve *cu);
void BKE_curve_type_test(struct Object *ob);
void BKE_curve_curve_dimension_update(struct Curve *cu);
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h
index 0711c423d1c..6775639125f 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_font.h
@@ -82,6 +82,8 @@ struct VFont *BKE_vfont_load(struct Main *bmain, const char *filepath);
struct VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists);
struct VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath);
+void BKE_vfont_make_local(struct Main *bmain, struct VFont *vfont, const bool lib_local);
+
bool BKE_vfont_to_curve_ex(struct Main *bmain, struct Object *ob, int mode,
struct ListBase *r_nubase,
const wchar_t **r_text, int *r_text_len, bool *r_text_free,
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 6159531d8bd..e9e3cd3b16e 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -56,6 +56,8 @@ struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src);
struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src);
struct bGPdata *gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
+void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
+
void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index 4f2c89070cb..09a069ee36f 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -43,6 +43,7 @@ struct Scene;
void BKE_group_free(struct Group *group);
struct Group *BKE_group_add(struct Main *bmain, const char *name);
struct Group *BKE_group_copy(struct Main *bmain, struct Group *group);
+void BKE_group_make_local(struct Main *bmain, struct Group *group, const bool lib_local);
bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
struct Group *BKE_group_object_find(struct Group *group, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
index 763a3874d4e..efef8d4be78 100644
--- a/source/blender/blenkernel/BKE_icons.h
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -55,7 +55,7 @@ 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);
-int BKE_icon_preview_ensure(struct PreviewImage *preview);
+int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
/* retrieve icon for id */
struct Icon *BKE_icon_get(int icon_id);
@@ -99,6 +99,8 @@ struct PreviewImage *BKE_previewimg_create(void);
/* create a copy of the preview image */
struct PreviewImage *BKE_previewimg_copy(struct PreviewImage *prv);
+void BKE_previewimg_id_copy(struct ID *new_id, struct ID *old_id);
+
/* retrieve existing or create new preview image */
struct PreviewImage *BKE_previewimg_id_ensure(struct ID *id);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 0895feef983..132c73209d1 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -108,7 +108,7 @@ struct anim *openanim_noload(const char *name, int flags, int streamindex, char
void BKE_image_de_interlace(struct Image *ima, int odd);
-void BKE_image_make_local(struct Main *bmain, struct Image *ima);
+void BKE_image_make_local(struct Main *bmain, struct Image *ima, const bool lib_local);
void BKE_image_tag_time(struct Image *ima);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index f30f9eac4e8..e590ff148d7 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -53,7 +53,6 @@ void BKE_key_free_nolib(struct Key *key);
struct Key *BKE_key_add(struct ID *id);
struct Key *BKE_key_copy(struct Main *bmain, struct Key *key);
struct Key *BKE_key_copy_nolib(struct Key *key);
-void BKE_key_make_local(struct Main *bmain, struct Key *key);
void BKE_key_sort(struct Key *key);
void key_curve_position_weights(float t, float data[4], int type);
diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h
index 49b43550e67..4d53850c572 100644
--- a/source/blender/blenkernel/BKE_lamp.h
+++ b/source/blender/blenkernel/BKE_lamp.h
@@ -46,7 +46,7 @@ void BKE_lamp_init(struct Lamp *la);
struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT;
struct Lamp *BKE_lamp_copy(struct Main *bmain, struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT;
-void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la);
+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);
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 606df9dcec8..226c82da295 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -49,7 +49,7 @@ void BKE_lattice_init(struct Lattice *lt);
struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name);
struct Lattice *BKE_lattice_copy(struct Main *bmain, struct Lattice *lt);
void BKE_lattice_free(struct Lattice *lt);
-void BKE_lattice_make_local(struct Main *bmain, 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;
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 396a3486b06..95d50fbd396 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -82,15 +82,17 @@ void id_us_min(struct ID *id);
void id_fake_user_set(struct ID *id);
void id_fake_user_clear(struct ID *id);
-bool id_make_local(struct Main *bmain, struct ID *id, bool test);
+void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_in_mainlist, const bool lib_local);
+bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local);
bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test);
void id_sort_by_name(struct ListBase *lb, struct ID *id);
void BKE_id_expand_local(struct ID *id);
+void BKE_id_copy_ensure_local(struct Main *bmain, struct ID *old_id, struct ID *new_id);
bool new_id(struct ListBase *lb, struct ID *id, const char *name);
void id_clear_lib_data(struct Main *bmain, struct ID *id);
-void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, bool id_in_mainlist);
+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);
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index e343cd29622..e96ef4e7be3 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -54,6 +54,8 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name);
void BKE_linestyle_free(FreestyleLineStyle *linestyle);
FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *linestyle);
+void BKE_linestyle_make_local(struct Main *bmain, struct FreestyleLineStyle *linestyle, const bool lib_local);
+
FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene);
LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h
index 97bfd0f3f07..3349bffac85 100644
--- a/source/blender/blenkernel/BKE_mask.h
+++ b/source/blender/blenkernel/BKE_mask.h
@@ -125,6 +125,8 @@ struct Mask *BKE_mask_new(struct Main *bmain, const char *name);
struct Mask *BKE_mask_copy_nolib(struct Mask *mask);
struct Mask *BKE_mask_copy(struct Main *bmain, struct Mask *mask);
+void BKE_mask_make_local(struct Main *bmain, struct Mask *mask, const bool lib_local);
+
void BKE_mask_free(struct Mask *mask);
void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]);
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 0bc54ee4a16..df739996c54 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -57,7 +57,7 @@ struct Material *BKE_material_add(struct Main *bmain, const char *name);
struct Material *BKE_material_copy(struct Main *bmain, struct Material *ma);
struct Material *localize_material(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
-void BKE_material_make_local(struct Main *bmain, struct Material *ma);
+void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local);
/* UNUSED */
// void automatname(struct Material *);
@@ -78,15 +78,13 @@ enum {
};
struct Material *give_current_material(struct Object *ob, short act);
-struct ID *material_from(struct Object *ob, short act);
void assign_material_id(struct ID *id, struct Material *ma, short act);
void assign_material(struct Object *ob, struct Material *ma, short act, int assign_type);
void assign_matarar(struct Object *ob, struct Material ***matar, short totcol);
-short find_material_index(struct Object *ob, struct Material *ma);
-
-bool object_add_material_slot(struct Object *ob);
-bool object_remove_material_slot(struct Object *ob);
+short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma);
+bool BKE_object_material_slot_add(struct Object *ob);
+bool BKE_object_material_slot_remove(struct Object *ob);
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 42704c1b2db..64320a20281 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -43,7 +43,7 @@ void BKE_mball_init(struct MetaBall *mb);
struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name);
struct MetaBall *BKE_mball_copy(struct Main *bmain, struct MetaBall *mb);
-void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb);
+void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool lib_local);
bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2);
bool BKE_mball_is_basis(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index d3bb34d7a41..d41878825bb 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -91,7 +91,7 @@ struct Mesh *BKE_mesh_copy(struct Main *bmain, 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);
-void BKE_mesh_make_local(struct Main *bmain, 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);
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index dff79b6cc22..b5b5443574c 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -125,6 +125,11 @@ void BKE_mesh_vert_edge_map_create(
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, int totvert, int totedge);
+void BKE_mesh_edge_loop_map_create(
+ MeshElemMap **r_map, int **r_mem,
+ const struct MEdge *medge, const int totedge,
+ const struct MPoly *mpoly, const int totpoly,
+ const struct MLoop *mloop, const int totloop);
void BKE_mesh_edge_poly_map_create(
MeshElemMap **r_map, int **r_mem,
const struct MEdge *medge, const int totedge,
@@ -186,11 +191,19 @@ typedef bool (*MeshRemapIslandsCalc)(
/* Above vert/UV mapping stuff does not do what we need here, but does things we do not need here.
* So better keep them separated for now, I think.
*/
-bool BKE_mesh_calc_islands_loop_poly_uv(
+bool BKE_mesh_calc_islands_loop_poly_edgeseam(
+ struct MVert *verts, const int totvert,
+ struct MEdge *edges, const int totedge,
+ struct MPoly *polys, const int totpoly,
+ struct MLoop *loops, const int totloop,
+ MeshIslandStore *r_island_store);
+
+bool BKE_mesh_calc_islands_loop_poly_uvmap(
struct MVert *verts, const int totvert,
struct MEdge *edges, const int totedge,
struct MPoly *polys, const int totpoly,
struct MLoop *loops, const int totloop,
+ const struct MLoopUV *luvs,
MeshIslandStore *r_island_store);
int *BKE_mesh_calc_smoothgroups(
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index b44cb226f0d..95f06e9f695 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -346,7 +346,7 @@ void ntreeUserDecrefID(struct bNodeTree *ntree);
struct bNodeTree *ntreeFromID(struct ID *id);
-void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist);
+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);
bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 1f0dc5f1814..1b3e05d11ae 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -107,7 +107,7 @@ struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene);
struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches);
struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob);
-void BKE_object_make_local(struct Main *bmain, struct Object *ob);
+void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool lib_local);
bool BKE_object_is_libdata(struct Object *ob);
bool BKE_object_obdata_is_libdata(struct Object *ob);
@@ -206,8 +206,6 @@ void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
-void BKE_object_eval_proxy_backlink(struct EvaluationContext *eval_ctx, struct Object *ob);
-
void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx,
struct Scene *scene,
struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 0b2e2383457..37831728e6f 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -324,7 +324,7 @@ struct ModifierData *object_add_particle_system(struct Scene *scene, struct Obje
void object_remove_particle_system(struct Scene *scene, struct Object *ob);
struct ParticleSettings *psys_new_settings(const char *name, struct Main *main);
struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, struct ParticleSettings *part);
-void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part);
+void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool lib_local);
void psys_reset(struct ParticleSystem *psys, int mode);
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 03af0b7d6c9..d2152950bff 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -101,6 +101,8 @@ struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name);
struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type);
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);
#ifdef DURIAN_CAMERA_SWITCH
struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 18d9fe061a8..28b15b2a310 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -80,6 +80,8 @@ void BKE_sound_load(struct Main *main, struct bSound *sound);
void BKE_sound_free(struct bSound *sound);
+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)
AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
#endif
diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h
index 89b948a2126..b91b64c4b74 100644
--- a/source/blender/blenkernel/BKE_speaker.h
+++ b/source/blender/blenkernel/BKE_speaker.h
@@ -34,7 +34,7 @@ struct Speaker;
void BKE_speaker_init(struct Speaker *spk);
void *BKE_speaker_add(struct Main *bmain, const char *name);
struct Speaker *BKE_speaker_copy(struct Main *bmain, struct Speaker *spk);
-void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk);
+void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk, const bool lib_local);
void BKE_speaker_free(struct Speaker *spk);
#endif
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index 858feeeab10..081b7589af6 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -53,6 +53,7 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha
const bool is_internal);
struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath);
struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta);
+void BKE_text_make_local (struct Main *bmain, struct Text *text, const bool lib_local);
void BKE_text_clear (struct Text *text);
void BKE_text_write (struct Text *text, const char *str);
int BKE_text_file_modified_check(struct Text *text);
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
index 56f056c681a..1c5ea946f59 100644
--- a/source/blender/blenkernel/BKE_texture.h
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -72,7 +72,7 @@ void BKE_texture_default(struct Tex *tex);
struct Tex *BKE_texture_copy(struct Main *bmain, struct Tex *tex);
struct Tex *BKE_texture_add(struct Main *bmain, const char *name);
struct Tex *BKE_texture_localize(struct Tex *tex);
-void BKE_texture_make_local(struct Main *bmain, struct Tex *tex);
+void BKE_texture_make_local(struct Main *bmain, struct Tex *tex, const bool lib_local);
void BKE_texture_type_set(struct Tex *tex, int type);
void BKE_texture_mtex_default(struct MTex *mtex);
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
index da5cca09b27..23bf9ec3d22 100644
--- a/source/blender/blenkernel/BKE_world.h
+++ b/source/blender/blenkernel/BKE_world.h
@@ -41,7 +41,7 @@ void BKE_world_init(struct World *wrld);
struct World *add_world(struct Main *bmian, const char *name);
struct World *BKE_world_copy(struct Main *bmain, struct World *wrld);
struct World *localize_world(struct World *wrld);
-void BKE_world_make_local(struct Main *bmain, struct World *wrld);
+void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool lib_local);
#endif
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 9007a6794a1..848ad252c45 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -70,7 +70,7 @@ set(SRC
intern/appdir.c
intern/armature.c
intern/armature_update.c
- intern/asset.c
+ intern/asset_engine.c
intern/autoexec.c
intern/blender.c
intern/blender_copybuffer.c
@@ -119,6 +119,7 @@ set(SRC
intern/lamp.c
intern/lattice.c
intern/library.c
+ intern/library_asset.c
intern/library_idmap.c
intern/library_query.c
intern/library_remap.c
@@ -195,7 +196,7 @@ set(SRC
BKE_animsys.h
BKE_appdir.h
BKE_armature.h
- BKE_asset.h
+ BKE_asset_engine.h
BKE_autoexec.h
BKE_blender.h
BKE_blender_copybuffer.h
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 828a6bb16ac..792e9195f12 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -313,12 +313,10 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *a
ss->osd_vao = 0;
ss->skip_grids = false;
ss->osd_compute = 0;
- ss->osd_uvs_invalid = true;
- ss->osd_subsurf_uv = 0;
- ss->osd_uv_index = -1;
ss->osd_next_face_ptex_index = 0;
ss->osd_coarse_coords = NULL;
ss->osd_num_coarse_coords = 0;
+ ss->osd_subdiv_uvs = false;
#endif
return ss;
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index a825cffe7a0..4c913e79586 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -205,7 +205,7 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, struct DerivedMesh *dm);
void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, struct DerivedMesh *dm);
/* Make sure GL mesh exists, up to date and ready to draw. */
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl);
+bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index);
/* Draw given partitions of the GL mesh.
*
@@ -244,6 +244,8 @@ void ccgSubSurf_free_osd_mesh(CCGSubSurf *ss);
void ccgSubSurf_getMinMax(CCGSubSurf *ss, float r_min[3], float r_max[3]);
+void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subsurf_uvs);
+
#endif
#endif /* __CCGSUBSURF_H__ */
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
index 7ec9f329444..9df1c9021ef 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h
@@ -86,7 +86,7 @@ void ccg_ehashIterator_next(EHashIterator *ehi);
int ccg_ehashIterator_isStopped(EHashIterator *ehi);
/**
- * Standard allocator implementarion.
+ * Standard allocator implementation.
*/
CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void);
@@ -255,10 +255,7 @@ struct CCGSubSurf {
*/
int osd_next_face_ptex_index;
- /* ** Needs review. ** */
- bool osd_subsurf_uv;
- int osd_uv_index;
- bool osd_uvs_invalid;
+ bool osd_subdiv_uvs;
#endif
};
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index 2bb55c2d1ed..65cf899b42b 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -190,7 +190,6 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
/* ** Make sure both GPU and CPU backends are properly reset. ** */
ss->osd_coarse_coords_invalid = true;
- ss->osd_uvs_invalid = true;
/* Reset GPU part. */
ss->osd_mesh_invalid = true;
@@ -216,7 +215,9 @@ static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
ss->osd_num_coarse_coords);
}
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
+bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
+ bool use_osd_glsl,
+ int active_uv_index)
{
int compute_type;
@@ -256,8 +257,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(
ss->osd_topology_refiner,
compute_type,
- ss->subdivLevels,
- ss->osd_subsurf_uv);
+ ss->subdivLevels);
ss->osd_topology_refiner = NULL;
if (UNLIKELY(ss->osd_mesh == NULL)) {
@@ -290,7 +290,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
ss->osd_coarse_coords_invalid = false;
}
- openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, ss->osd_uv_index);
+ openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, active_uv_index);
return true;
}
@@ -984,6 +984,11 @@ void ccgSubSurf__delete_pending(void)
BLI_spin_unlock(&delete_spin);
}
+void ccgSubSurf__sync_subdivUvs(CCGSubSurf *ss, bool subdiv_uvs)
+{
+ ss->osd_subdiv_uvs = subdiv_uvs;
+}
+
/* ** Public API ** */
void BKE_subsurf_osd_init(void)
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
index c4317f4d740..f1f82f458aa 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
@@ -62,6 +62,16 @@ typedef struct ConvDMStorage {
*vert_poly_mem,
*edge_poly_mem;
#endif
+
+ MVert *mvert;
+ MEdge *medge;
+ MLoop *mloop;
+ MPoly *mpoly;
+
+ MeshIslandStore island_store;
+ int num_uvs;
+ float *uvs;
+ int *face_uvs;
} ConvDMStorage;
static OpenSubdiv_SchemeType conv_dm_get_type(
@@ -74,6 +84,13 @@ static OpenSubdiv_SchemeType conv_dm_get_type(
return OSD_SCHEME_CATMARK;
}
+static bool conv_dm_get_subdiv_uvs(
+ const OpenSubdiv_Converter *converter)
+{
+ ConvDMStorage *storage = converter->user_data;
+ return (storage->ss->osd_subdiv_uvs);
+}
+
static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter)
{
ConvDMStorage *storage = converter->user_data;
@@ -99,9 +116,7 @@ static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter,
int face)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- const MPoly *mp = dm->getPolyArray(dm);
- const MPoly *mpoly = &mp[face];
+ const MPoly *mpoly = &storage->mpoly[face];
return mpoly->totloop;
}
@@ -110,13 +125,10 @@ static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter,
int *face_verts)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
- const MPoly *mpoly = &mp[face];
+ const MPoly *mpoly = &storage->mpoly[face];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- face_verts[loop] = ml[mpoly->loopstart + loop].v;
+ face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v;
}
}
@@ -125,13 +137,10 @@ static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter,
int *face_edges)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
- const MPoly *mpoly = &mp[face];
+ const MPoly *mpoly = &storage->mpoly[face];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- face_edges[loop] = ml[mpoly->loopstart + loop].e;
+ face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e;
}
}
@@ -140,9 +149,7 @@ static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter,
int *edge_verts)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
- const MEdge *me = dm->getEdgeArray(dm);
- const MEdge *medge = &me[edge];
+ const MEdge *medge = &storage->medge[edge];
edge_verts[0] = medge->v1;
edge_verts[1] = medge->v2;
}
@@ -153,14 +160,12 @@ static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
int num = 0, poly;
for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &mp[poly];
+ const MPoly *mpoly = &user_data->mpoly[poly];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &ml[mpoly->loopstart + loop];
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->e == edge) {
++num;
break;
@@ -180,14 +185,12 @@ static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
int num = 0, poly;
for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &mp[poly];
+ const MPoly *mpoly = &user_data->mpoly[poly];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &ml[mpoly->loopstart + loop];
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->e == edge) {
edge_faces[num++] = poly;
break;
@@ -205,9 +208,8 @@ static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter,
int edge)
{
ConvDMStorage *storage = converter->user_data;
- DerivedMesh *dm = storage->dm;
CCGSubSurf *ss = storage->ss;
- const MEdge *medge = dm->getEdgeArray(dm);
+ const MEdge *medge = storage->medge;
return (float)medge[edge].crease / 255.0f * ss->subdivLevels;
}
@@ -217,10 +219,9 @@ static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MEdge *me = dm->getEdgeArray(dm);
int num = 0, edge;
for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &me[edge];
+ const MEdge *medge = &user_data->medge[edge];
if (medge->v1 == vert || medge->v2 == vert) {
++num;
}
@@ -238,10 +239,9 @@ static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MEdge *me = dm->getEdgeArray(dm);
int num = 0, edge;
for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
- const MEdge *medge = &me[edge];
+ const MEdge *medge = &user_data->medge[edge];
if (medge->v1 == vert || medge->v2 == vert) {
vert_edges[num++] = edge;
}
@@ -259,14 +259,12 @@ static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
int num = 0, poly;
for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &mp[poly];
+ const MPoly *mpoly = &user_data->mpoly[poly];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &ml[mpoly->loopstart + loop];
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->v == vert) {
++num;
break;
@@ -286,14 +284,12 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
ConvDMStorage *storage = converter->user_data;
#ifndef USE_MESH_ELEMENT_MAPPING
DerivedMesh *dm = storage->dm;
- const MLoop *ml = dm->getLoopArray(dm);
- const MPoly *mp = dm->getPolyArray(dm);
int num = 0, poly;
for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
- const MPoly *mpoly = &mp[poly];
+ const MPoly *mpoly = &storage->mpoly[poly];
int loop;
for (loop = 0; loop < mpoly->totloop; loop++) {
- const MLoop *mloop = &ml[mpoly->loopstart + loop];
+ const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
if (mloop->v == vert) {
vert_faces[num++] = poly;
break;
@@ -307,9 +303,114 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
#endif
}
+static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter)
+{
+ ConvDMStorage *storage = converter->user_data;
+ DerivedMesh *dm = storage->dm;
+ int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
+ return num_uv_layers;
+}
+
+static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter,
+ int layer)
+{
+ ConvDMStorage *storage = converter->user_data;
+ DerivedMesh *dm = storage->dm;
+
+ const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer);
+ const int num_loops = dm->getNumLoops(dm);
+
+ /* Initialize memory required for the operations. */
+ if (storage->uvs == NULL) {
+ storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs");
+ }
+ if (storage->face_uvs == NULL) {
+ storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs");
+ }
+
+ /* Calculate islands connectivity of the UVs. */
+ BKE_mesh_calc_islands_loop_poly_uvmap(
+ storage->mvert, dm->getNumVerts(dm),
+ storage->medge, dm->getNumEdges(dm),
+ storage->mpoly, dm->getNumPolys(dm),
+ storage->mloop, dm->getNumLoops(dm),
+ mloopuv,
+ &storage->island_store);
+
+ /* Here we "weld" duplicated vertices from island to the same UV value.
+ * The idea here is that we need to pass individual islands to OpenSubdiv.
+ */
+ storage->num_uvs = 0;
+ for (int island = 0; island < storage->island_store.islands_num; ++island) {
+ MeshElemMap *island_poly_map = storage->island_store.islands[island];
+ for (int poly = 0; poly < island_poly_map->count; ++poly) {
+ int poly_index = island_poly_map->indices[poly];
+ /* Within the same UV island we should share UV points across
+ * loops. Otherwise each poly will be subdivided individually
+ * which we don't really want.
+ */
+ const MPoly *mpoly = &storage->mpoly[poly_index];
+ for (int loop = 0; loop < mpoly->totloop; ++loop) {
+ const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop];
+ bool found = false;
+ /* TODO(sergey): Quite bad loop, which gives us O(N^2)
+ * complexity here. But how can we do it smarter, hopefully
+ * without requiring lots of additional memory.
+ */
+ for (int i = 0; i < storage->num_uvs; ++i) {
+ if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) {
+ storage->face_uvs[mpoly->loopstart + loop] = i;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv);
+ storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs;
+ ++storage->num_uvs;
+ }
+ }
+ }
+ }
+}
+
+static void conv_dm_finish_uv_layer(const OpenSubdiv_Converter *converter)
+{
+ ConvDMStorage *storage = converter->user_data;
+ BKE_mesh_loop_islands_free(&storage->island_store);
+}
+
+static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter)
+{
+ ConvDMStorage *storage = converter->user_data;
+ 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)
+{
+ ConvDMStorage *storage = converter->user_data;
+ const MPoly *mpoly = &storage->mpoly[face];
+ return storage->face_uvs[mpoly->loopstart + corner];
+}
+
static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter)
{
ConvDMStorage *user_data = converter->user_data;
+ if (user_data->uvs != NULL) {
+ MEM_freeN(user_data->uvs);
+ }
+ if (user_data->face_uvs != NULL) {
+ MEM_freeN(user_data->face_uvs);
+ }
+
#ifdef USE_MESH_ELEMENT_MAPPING
MEM_freeN(user_data->vert_edge_map);
MEM_freeN(user_data->vert_edge_mem);
@@ -330,6 +431,8 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
converter->get_type = conv_dm_get_type;
+ converter->get_subdiv_uvs = conv_dm_get_subdiv_uvs;
+
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;
@@ -348,9 +451,27 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
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;
+
user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
user_data->ss = ss;
user_data->dm = dm;
+
+ user_data->mvert = dm->getVertArray(dm);
+ user_data->medge = dm->getEdgeArray(dm);
+ user_data->mloop = dm->getLoopArray(dm);
+ user_data->mpoly = dm->getPolyArray(dm);
+
+ memset(&user_data->island_store, 0, sizeof(user_data->island_store));
+
+ user_data->uvs = NULL;
+ user_data->face_uvs = NULL;
+
converter->free_user_data = conv_dm_free_user_data;
converter->user_data = user_data;
@@ -405,6 +526,13 @@ static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(
}
}
+static bool conv_ccg_get_subdiv_uvs(
+ const OpenSubdiv_Converter *converter)
+{
+ CCGSubSurf *ss = converter->user_data;
+ return (ss->osd_subdiv_uvs);
+}
+
static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter)
{
CCGSubSurf *ss = converter->user_data;
@@ -548,11 +676,44 @@ static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter,
}
}
+static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter))
+{
+ return 0;
+}
+
+static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter * UNUSED(converter),
+ int UNUSED(layer))
+{
+}
+
+static void conv_ccg_finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter))
+{
+}
+
+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_))
+{
+ return 0;
+}
+
void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
OpenSubdiv_Converter *converter)
{
converter->get_type = conv_ccg_get_bilinear_type;
+ converter->get_subdiv_uvs = conv_ccg_get_subdiv_uvs;
+
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;
@@ -571,6 +732,13 @@ void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
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->user_data = ss;
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_util.c b/source/blender/blenkernel/intern/CCGSubSurf_util.c
index 9af69115559..c7ef528c02f 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_util.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_util.c
@@ -184,7 +184,7 @@ int ccg_ehashIterator_isStopped(EHashIterator *ehi)
}
/**
- * Standard allocator implementarion.
+ * Standard allocator implementation.
*/
static void *_stdAllocator_alloc(CCGAllocatorHDL UNUSED(a), int numBytes)
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index f7ff1261c8a..470098f8c7c 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -95,34 +95,9 @@ bAction *add_empty_action(Main *bmain, const char name[])
/* .................................. */
// does copy_fcurve...
-void BKE_action_make_local(Main *bmain, bAction *act)
+void BKE_action_make_local(Main *bmain, bAction *act, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(act)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, act, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &act->id);
- BKE_id_expand_local(&act->id);
- }
- else {
- bAction *act_new = BKE_action_copy(bmain, act);
-
- act_new->id.us = 0;
-
- BKE_libblock_remap(bmain, act, act_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &act->id, true, lib_local);
}
/* .................................. */
@@ -181,10 +156,7 @@ bAction *BKE_action_copy(Main *bmain, bAction *src)
}
}
- if (ID_IS_LINKED_DATABLOCK(src)) {
- BKE_id_expand_local(&dst->id);
- BKE_id_lib_local_paths(bmain, src->id.lib, &dst->id);
- }
+ BKE_id_copy_ensure_local(bmain, &src->id, &dst->id);
return dst;
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index d6f93528262..d04b950c043 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -400,8 +400,8 @@ static void make_local_strips(ListBase *strips)
NlaStrip *strip;
for (strip = strips->first; strip; strip = strip->next) {
- if (strip->act) BKE_action_make_local(G.main, strip->act);
- if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target);
+ if (strip->act) BKE_action_make_local(G.main, strip->act, false);
+ if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target, false);
make_local_strips(&strip->strips);
}
@@ -413,10 +413,10 @@ void BKE_animdata_make_local(AnimData *adt)
NlaTrack *nlt;
/* Actions - Active and Temp */
- if (adt->action) BKE_action_make_local(G.main, adt->action);
- if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact);
+ if (adt->action) BKE_action_make_local(G.main, adt->action, false);
+ if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact, false);
/* Remaps */
- if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target);
+ if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target, false);
/* Drivers */
/* TODO: need to remap the ID-targets too? */
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 5f564e1c4d2..c644fe09364 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -144,34 +144,9 @@ void BKE_armature_free(bArmature *arm)
}
}
-void BKE_armature_make_local(Main *bmain, bArmature *arm)
+void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(arm)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, arm, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &arm->id);
- BKE_id_expand_local(&arm->id);
- }
- else {
- bArmature *arm_new = BKE_armature_copy(bmain, arm);
-
- arm_new->id.us = 0;
-
- BKE_libblock_remap(bmain, arm, arm_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &arm->id, true, lib_local);
}
static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone **newActBone)
@@ -219,10 +194,7 @@ bArmature *BKE_armature_copy(Main *bmain, bArmature *arm)
newArm->act_edbone = NULL;
newArm->sketch = NULL;
- if (ID_IS_LINKED_DATABLOCK(arm)) {
- BKE_id_expand_local(&newArm->id);
- BKE_id_lib_local_paths(bmain, arm->id.lib, &newArm->id);
- }
+ BKE_id_copy_ensure_local(bmain, &arm->id, &newArm->id);
return newArm;
}
@@ -1931,6 +1903,17 @@ static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int
return counter;
}
+/**
+ * Clear pointers of object's pose (needed in remap case, since we cannot always wait for a complete pose rebuild).
+ */
+void BKE_pose_clear_pointers(bPose *pose)
+{
+ for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ pchan->bone = NULL;
+ pchan->child = NULL;
+ }
+}
+
/* only after leave editmode, duplicating, validating older files, library syncing */
/* NOTE: pose->flag is set for it */
void BKE_pose_rebuild(Object *ob, bArmature *arm)
@@ -1951,10 +1934,7 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm)
pose = ob->pose;
/* clear */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- pchan->bone = NULL;
- pchan->child = NULL;
- }
+ BKE_pose_clear_pointers(pose);
/* first step, check if all channels are there */
for (bone = arm->bonebase.first; bone; bone = bone->next) {
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index ece17335fa0..ef8a2f100dc 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -224,7 +224,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
}
/* make a new Spline-IK chain, and store it in the IK chains */
- /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */
+ /* TODO: we should check if there is already an IK chain on this, since that would take precedence... */
{
/* make new tree */
tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree");
@@ -696,7 +696,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx),
void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob)
{
- BLI_assert(ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL);
+ BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL);
DEBUG_PRINT("%s on %s\n", __func__, ob->id.name);
if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) {
printf("Proxy copy error, lib Object: %s proxy Object: %s\n",
diff --git a/source/blender/blenkernel/intern/asset.c b/source/blender/blenkernel/intern/asset_engine.c
index 3f4894d41c5..8fa651bdef1 100644
--- a/source/blender/blenkernel/intern/asset.c
+++ b/source/blender/blenkernel/intern/asset_engine.c
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/blenkernel/intern/asset.c
+/** \file blender/blenkernel/intern/asset_engine.c
* \ingroup bke
*/
@@ -48,7 +48,7 @@
#include "PIL_time.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_library.h"
@@ -405,7 +405,7 @@ void BKE_filedir_entryarr_clear(FileDirEntryArr *array)
array->nbr_entries_filtered = 0;
}
-/* GHash helpers */
+/* Various helpers */
unsigned int BKE_asset_uuid_hash(const void *key)
{
return BLI_hash_mm2((const unsigned char *)key, sizeof(AssetUUID), 0);
@@ -418,4 +418,11 @@ bool BKE_asset_uuid_cmp(const void *a, const void *b)
return !ASSETUUID_COMPARE(uuid1, uuid2); /* Expects false when compared equal... */
}
-
+void BKE_asset_uuid_print(const AssetUUID *uuid)
+{
+ /* TODO print nicer (as 128bit hexadecimal...). */
+ printf("[%d,%d,%d,%d][%d,%d,%d,%d][%d,%d,%d,%d]\n",
+ uuid->uuid_asset[0], uuid->uuid_asset[1], uuid->uuid_asset[2], uuid->uuid_asset[3],
+ uuid->uuid_variant[0], uuid->uuid_variant[1], uuid->uuid_variant[2], uuid->uuid_variant[3],
+ uuid->uuid_revision[0], uuid->uuid_revision[1], uuid->uuid_revision[2], uuid->uuid_revision[3]);
+}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 25491bcb998..3740fdca740 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -47,7 +47,7 @@
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_blender.h" /* own include */
#include "BKE_blender_version.h" /* own include */
#include "BKE_blendfile.h"
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index a708c59fa97..d079583f9a8 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -424,7 +424,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
{
const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
- if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED_DATABLOCK(id)) {
+ if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED(id)) {
return;
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 20621feac6c..da58ad332ba 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -197,10 +197,7 @@ Brush *BKE_brush_copy(Main *bmain, Brush *brush)
/* enable fake user by default */
id_fake_user_set(&brush->id);
- if (ID_IS_LINKED_DATABLOCK(brush)) {
- BKE_id_expand_local(&brushn->id);
- BKE_id_lib_local_paths(bmain, brush->id.lib, &brushn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &brush->id, &brushn->id);
return brushn;
}
@@ -219,27 +216,27 @@ void BKE_brush_free(Brush *brush)
BKE_previewimg_free(&(brush->preview));
}
-void BKE_brush_make_local(Main *bmain, Brush *brush)
+void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local)
{
bool is_local = false, is_lib = false;
- /* - only lib users: do nothing
+ /* - only lib users: do nothing (unless force_local is set)
* - only local users: set flag
* - mixed: make copy
*/
- if (!ID_IS_LINKED_DATABLOCK(brush)) {
+ if (!ID_IS_LINKED(brush)) {
return;
}
if (brush->clone.image) {
/* Special case: ima always local immediately. Clone image should only have one user anyway. */
- id_make_local(bmain, &brush->clone.image->id, false);
+ id_make_local(bmain, &brush->clone.image->id, false, false);
}
BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib);
- if (is_local) {
+ if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data(bmain, &brush->id);
BKE_id_expand_local(&brush->id);
@@ -252,7 +249,9 @@ void BKE_brush_make_local(Main *bmain, Brush *brush)
brush_new->id.us = 0;
- BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ if (!lib_local) {
+ BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index ae7aac8b54f..85ce399b770 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -78,8 +78,8 @@ void BKE_camera_init(Camera *cam)
/* stereoscopy 3d */
cam->stereo.interocular_distance = 0.065f;
cam->stereo.convergence_distance = 30.f * 0.065f;
- cam->stereo.pole_merge_angle_from = DEG2RAD(60.0f);
- cam->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
+ cam->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
+ cam->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
}
void *BKE_camera_add(Main *bmain, const char *name)
@@ -99,42 +99,14 @@ Camera *BKE_camera_copy(Main *bmain, Camera *cam)
camn = BKE_libblock_copy(bmain, &cam->id);
- if (ID_IS_LINKED_DATABLOCK(cam)) {
- BKE_id_expand_local(&camn->id);
- BKE_id_lib_local_paths(bmain, cam->id.lib, &camn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &cam->id, &camn->id);
return camn;
}
-void BKE_camera_make_local(Main *bmain, Camera *cam)
+void BKE_camera_make_local(Main *bmain, Camera *cam, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(cam)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, cam, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &cam->id);
- BKE_id_expand_local(&cam->id);
- }
- else {
- Camera *cam_new = BKE_camera_copy(bmain, cam);
-
- cam_new->id.us = 0;
-
- BKE_libblock_remap(bmain, cam, cam_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &cam->id, true, lib_local);
}
/** Free (or release) any data used by this camera (does not free the camera itself). */
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index 2932939b208..53a74024c51 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -982,6 +982,7 @@ static void save_sample_line(Scopes *scopes, const int idx, const float fx, cons
/* waveform */
switch (scopes->wavefrm_mode) {
case SCOPES_WAVEFRM_RGB:
+ case SCOPES_WAVEFRM_RGB_PARADE:
scopes->waveform_1[idx + 0] = fx;
scopes->waveform_1[idx + 1] = rgb[0];
scopes->waveform_2[idx + 0] = fx;
@@ -1265,6 +1266,8 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *
switch (scopes->wavefrm_mode) {
case SCOPES_WAVEFRM_RGB:
+ /* fall-through */
+ case SCOPES_WAVEFRM_RGB_PARADE:
ycc_mode = -1;
break;
case SCOPES_WAVEFRM_LUMA:
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 4c9ddd495e3..1f2cc2e4ad8 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -4649,7 +4649,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use
/* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */
static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData))
{
- if (*idpoin && ID_IS_LINKED_DATABLOCK(*idpoin))
+ if (*idpoin && ID_IS_LINKED(*idpoin))
id_lib_extern(*idpoin);
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 0e634e21ea3..90a514781d7 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -207,45 +207,14 @@ Curve *BKE_curve_copy(Main *bmain, Curve *cu)
id_us_plus((ID *)cun->vfonti);
id_us_plus((ID *)cun->vfontbi);
- if (ID_IS_LINKED_DATABLOCK(cu)) {
- BKE_id_expand_local(&cun->id);
- BKE_id_lib_local_paths(bmain, cu->id.lib, &cun->id);
- }
+ BKE_id_copy_ensure_local(bmain, &cu->id, &cun->id);
return cun;
}
-void BKE_curve_make_local(Main *bmain, Curve *cu)
+void BKE_curve_make_local(Main *bmain, Curve *cu, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - when there are only lib users: don't do
- * - when there are only local users: set flag
- * - mixed: do a copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(cu)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, cu, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &cu->id);
- if (cu->key) {
- BKE_key_make_local(bmain, cu->key);
- }
- BKE_id_expand_local(&cu->id);
- }
- else {
- Curve *cu_new = BKE_curve_copy(bmain, cu);
-
- cu_new->id.us = 0;
-
- BKE_libblock_remap(bmain, cu, cu_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &cu->id, true, lib_local);
}
/* Get list of nurbs from editnurbs structure */
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 7292ed2b5c5..839673c192b 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -356,7 +356,7 @@ static MeshRemapIslandsCalc data_transfer_get_loop_islands_generator(const int c
{
switch (cddata_type) {
case CD_FAKE_UV:
- return BKE_mesh_calc_islands_loop_poly_uv;
+ return BKE_mesh_calc_islands_loop_poly_edgeseam;
default:
break;
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 2b097f31c59..d35de6fc5d3 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -4483,7 +4483,7 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus
CLAMP_MIN(max_velocity, vel);
}
- steps = (int)ceil(max_velocity / bData->average_dist * timescale);
+ steps = (int)ceil((double)max_velocity / bData->average_dist * (double)timescale);
CLAMP(steps, 0, 12);
eff_scale = brush->smudge_strength / (float)steps * timescale;
@@ -4634,7 +4634,7 @@ static int dynamicPaint_prepareEffectStep(
/* calculate average values (single thread) */
for (int index = 0; index < sData->total_points; index++) {
- average_force += (*force)[index * 4 + 3];
+ average_force += (double)(*force)[index * 4 + 3];
}
average_force /= sData->total_points;
}
@@ -4651,7 +4651,7 @@ static int dynamicPaint_prepareEffectStep(
shrink_speed = surface->shrink_speed;
fastest_effect = max_fff(spread_speed, shrink_speed, average_force);
- avg_dist = bData->average_dist * CANVAS_REL_SIZE / getSurfaceDimension(sData);
+ avg_dist = bData->average_dist * (double)CANVAS_REL_SIZE / (double)getSurfaceDimension(sData);
steps = (int)ceilf(1.5f * EFF_MOVEMENT_PER_FRAME * fastest_effect / avg_dist * timescale);
CLAMP(steps, 1, 20);
@@ -5009,7 +5009,8 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
const float wave_scale = CANVAS_REL_SIZE / canvas_size;
/* allocate memory */
- PaintWavePoint *prevPoint = MEM_mallocN(sData->total_points * sizeof(PaintWavePoint), "Temp previous points for wave simulation");
+ PaintWavePoint *prevPoint = MEM_mallocN(
+ sData->total_points * sizeof(PaintWavePoint), __func__);
if (!prevPoint)
return;
@@ -5019,13 +5020,14 @@ static void dynamicPaint_doWaveStep(DynamicPaintSurface *surface, float timescal
int numOfNeighs = sData->adj_data->n_num[index];
for (i = 0; i < numOfNeighs; i++) {
- average_dist += bNeighs[sData->adj_data->n_index[index] + i].dist;
+ average_dist += (double)bNeighs[sData->adj_data->n_index[index] + i].dist;
}
}
- average_dist *= wave_scale / sData->adj_data->total_targets;
+ average_dist *= (double)wave_scale / sData->adj_data->total_targets;
/* determine number of required steps */
- steps = (int)ceil((WAVE_TIME_FAC * timescale * surface->wave_timescale) / (average_dist / wave_speed / 3));
+ steps = (int)ceil((double)(WAVE_TIME_FAC * timescale * surface->wave_timescale) /
+ (average_dist / (double)wave_speed / 3));
CLAMP(steps, 1, 20);
timescale /= steps;
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 5e1f8814ed6..580842fe176 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -309,6 +309,11 @@ VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath)
return BKE_vfont_load_exists_ex(bmain, filepath, NULL);
}
+void BKE_vfont_make_local(Main *bmain, VFont *vfont, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &vfont->id, true, lib_local);
+}
+
static VFont *which_vfont(Curve *cu, CharInfo *info)
{
switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) {
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index ac4f566dc62..8621da0d42e 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -390,6 +390,11 @@ bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *src, bool internal_copy)
return dst;
}
+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 --------- */
/* ensure selection status of stroke is in sync with its points */
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 11bbd91e9c9..9b011dbb003 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -97,14 +97,16 @@ Group *BKE_group_copy(Main *bmain, Group *group)
/* Do not copy group's preview (same behavior as for objects). */
groupn->preview = NULL;
- if (ID_IS_LINKED_DATABLOCK(group)) {
- BKE_id_expand_local(&groupn->id);
- BKE_id_lib_local_paths(bmain, group->id.lib, &groupn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &group->id, &groupn->id);
return groupn;
}
+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)
{
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index f3e86b44459..2d5b15c8f9d 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -221,6 +221,24 @@ PreviewImage *BKE_previewimg_copy(PreviewImage *prv)
return prv_img;
}
+/** Duplicate preview image from \a id and clear icon_id, to be used by datablock copy functions. */
+void BKE_previewimg_id_copy(ID *new_id, ID *old_id)
+{
+ PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
+ PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
+
+ if (old_prv_p && *old_prv_p) {
+ BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p));
+// const int new_icon_id = get_next_free_id();
+
+// if (new_icon_id == 0) {
+// return; /* Failure. */
+// }
+ *new_prv_p = BKE_previewimg_copy(*old_prv_p);
+ new_id->icon_id = (*new_prv_p)->icon_id = 0;
+ }
+}
+
PreviewImage **BKE_previewimg_id_get_p(ID *id)
{
switch (GS(id->name)) {
@@ -423,10 +441,26 @@ void BKE_icon_changed(int id)
}
}
-int BKE_icon_id_ensure(struct ID *id)
+static int icon_id_ensure_create_icon(struct ID *id)
{
Icon *new_icon = NULL;
+ new_icon = MEM_mallocN(sizeof(Icon), __func__);
+
+ new_icon->obj = id;
+ new_icon->type = GS(id->name);
+
+ /* next two lines make sure image gets created */
+ new_icon->drawinfo = NULL;
+ new_icon->drawinfo_free = NULL;
+
+ BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon);
+
+ return id->icon_id;
+}
+
+int BKE_icon_id_ensure(struct ID *id)
+{
if (!id || G.background)
return 0;
@@ -440,32 +474,39 @@ int BKE_icon_id_ensure(struct ID *id)
return 0;
}
- new_icon = MEM_mallocN(sizeof(Icon), __func__);
-
- new_icon->obj = id;
- new_icon->type = GS(id->name);
-
- /* next two lines make sure image gets created */
- new_icon->drawinfo = NULL;
- new_icon->drawinfo_free = NULL;
+ /* Ensure we synchronize ID icon_id with its previewimage if it has one. */
+ PreviewImage **p_prv = BKE_previewimg_id_get_p(id);
+ if (p_prv && *p_prv) {
+ BLI_assert(ELEM((*p_prv)->icon_id, 0, id->icon_id));
+ (*p_prv)->icon_id = id->icon_id;
+ }
- BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon);
-
- return id->icon_id;
+ return icon_id_ensure_create_icon(id);
}
/**
* Return icon id of given preview, or create new icon if not found.
*/
-int BKE_icon_preview_ensure(PreviewImage *preview)
+int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
{
Icon *new_icon = NULL;
if (!preview || G.background)
return 0;
- if (preview->icon_id)
+ if (id) {
+ BLI_assert(BKE_previewimg_id_ensure(id) == preview);
+ }
+
+ if (preview->icon_id) {
+ BLI_assert(!id || !id->icon_id || id->icon_id == preview->icon_id);
+ return preview->icon_id;
+ }
+
+ if (id && id->icon_id) {
+ preview->icon_id = id->icon_id;
return preview->icon_id;
+ }
preview->icon_id = get_next_free_id();
@@ -474,6 +515,12 @@ int BKE_icon_preview_ensure(PreviewImage *preview)
return 0;
}
+ /* Ensure we synchronize ID icon_id with its previewimage if available, and generate suitable 'ID' icon. */
+ if (id) {
+ id->icon_id = preview->icon_id;
+ return icon_id_ensure_create_icon(id);
+ }
+
new_icon = MEM_mallocN(sizeof(Icon), __func__);
new_icon->obj = preview;
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index f6f38977402..ea28dabb945 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -456,47 +456,20 @@ Image *BKE_image_copy(Main *bmain, Image *ima)
copy_image_packedfiles(&nima->packedfiles, &ima->packedfiles);
- nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format);
+ /* nima->stere3d_format is already allocated by image_alloc... */
+ *nima->stereo3d_format = *ima->stereo3d_format;
BLI_duplicatelist(&nima->views, &ima->views);
- nima->preview = BKE_previewimg_copy(ima->preview);
+ BKE_previewimg_id_copy(&nima->id, &ima->id);
- if (ID_IS_LINKED_DATABLOCK(ima)) {
- BKE_id_expand_local(&nima->id);
- BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ima->id, &nima->id);
return nima;
}
-void BKE_image_make_local(Main *bmain, Image *ima)
+void BKE_image_make_local(Main *bmain, Image *ima, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(ima)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, ima, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &ima->id);
- BKE_id_expand_local(&ima->id);
- }
- else {
- Image *ima_new = BKE_image_copy(bmain, ima);
-
- ima_new->id.us = 0;
-
- BKE_libblock_remap(bmain, ima, ima_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &ima->id, true, lib_local);
}
void BKE_image_merge(Image *dest, Image *source)
@@ -1083,43 +1056,55 @@ int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options)
{
memset(r_options, 0, sizeof(*r_options));
- if (imtype == R_IMF_IMTYPE_TARGA)
+ if (imtype == R_IMF_IMTYPE_TARGA) {
return IMB_FTYPE_TGA;
+ }
else if (imtype == R_IMF_IMTYPE_RAWTGA) {
r_options->flag = RAWTGA;
return IMB_FTYPE_TGA;
}
- else if (imtype == R_IMF_IMTYPE_IRIS)
+ else if (imtype == R_IMF_IMTYPE_IRIS) {
return IMB_FTYPE_IMAGIC;
+ }
#ifdef WITH_HDR
- else if (imtype == R_IMF_IMTYPE_RADHDR)
+ else if (imtype == R_IMF_IMTYPE_RADHDR) {
return IMB_FTYPE_RADHDR;
+ }
#endif
else if (imtype == R_IMF_IMTYPE_PNG) {
r_options->quality = 15;
return IMB_FTYPE_PNG;
}
#ifdef WITH_DDS
- else if (imtype == R_IMF_IMTYPE_DDS)
+ else if (imtype == R_IMF_IMTYPE_DDS) {
return IMB_FTYPE_DDS;
+ }
#endif
- else if (imtype == R_IMF_IMTYPE_BMP)
+ else if (imtype == R_IMF_IMTYPE_BMP) {
return IMB_FTYPE_BMP;
+ }
#ifdef WITH_TIFF
- else if (imtype == R_IMF_IMTYPE_TIFF)
+ else if (imtype == R_IMF_IMTYPE_TIFF) {
return IMB_FTYPE_TIF;
+ }
#endif
- else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER)
+ else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) {
return IMB_FTYPE_OPENEXR;
+ }
#ifdef WITH_CINEON
- else if (imtype == R_IMF_IMTYPE_CINEON)
+ else if (imtype == R_IMF_IMTYPE_CINEON) {
return IMB_FTYPE_CINEON;
- else if (imtype == R_IMF_IMTYPE_DPX)
+ }
+ else if (imtype == R_IMF_IMTYPE_DPX) {
return IMB_FTYPE_DPX;
+ }
#endif
#ifdef WITH_OPENJPEG
- else if (imtype == R_IMF_IMTYPE_JP2)
+ else if (imtype == R_IMF_IMTYPE_JP2) {
+ r_options->flag |= JP2_JP2;
+ r_options->quality = 90;
return IMB_FTYPE_JP2;
+ }
#endif
else {
r_options->quality = 90;
@@ -1129,46 +1114,60 @@ int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options)
char BKE_image_ftype_to_imtype(const int ftype, const ImbFormatOptions *options)
{
- if (ftype == 0)
+ if (ftype == 0) {
return R_IMF_IMTYPE_TARGA;
- else if (ftype == IMB_FTYPE_IMAGIC)
+ }
+ else if (ftype == IMB_FTYPE_IMAGIC) {
return R_IMF_IMTYPE_IRIS;
+ }
#ifdef WITH_HDR
- else if (ftype == IMB_FTYPE_RADHDR)
+ else if (ftype == IMB_FTYPE_RADHDR) {
return R_IMF_IMTYPE_RADHDR;
+ }
#endif
- else if (ftype == IMB_FTYPE_PNG)
+ else if (ftype == IMB_FTYPE_PNG) {
return R_IMF_IMTYPE_PNG;
+ }
#ifdef WITH_DDS
- else if (ftype == IMB_FTYPE_DDS)
+ else if (ftype == IMB_FTYPE_DDS) {
return R_IMF_IMTYPE_DDS;
+ }
#endif
- else if (ftype == IMB_FTYPE_BMP)
+ else if (ftype == IMB_FTYPE_BMP) {
return R_IMF_IMTYPE_BMP;
+ }
#ifdef WITH_TIFF
- else if (ftype == IMB_FTYPE_TIF)
+ else if (ftype == IMB_FTYPE_TIF) {
return R_IMF_IMTYPE_TIFF;
+ }
#endif
- else if (ftype == IMB_FTYPE_OPENEXR)
+ else if (ftype == IMB_FTYPE_OPENEXR) {
return R_IMF_IMTYPE_OPENEXR;
+ }
#ifdef WITH_CINEON
- else if (ftype == IMB_FTYPE_CINEON)
+ else if (ftype == IMB_FTYPE_CINEON) {
return R_IMF_IMTYPE_CINEON;
- else if (ftype == IMB_FTYPE_DPX)
+ }
+ else if (ftype == IMB_FTYPE_DPX) {
return R_IMF_IMTYPE_DPX;
+ }
#endif
else if (ftype == IMB_FTYPE_TGA) {
- if (options && (options->flag & RAWTGA))
+ if (options && (options->flag & RAWTGA)) {
return R_IMF_IMTYPE_RAWTGA;
- else
+ }
+ else {
return R_IMF_IMTYPE_TARGA;
+ }
}
#ifdef WITH_OPENJPEG
- else if (ftype == IMB_FTYPE_JP2)
+ else if (ftype == IMB_FTYPE_JP2) {
return R_IMF_IMTYPE_JP2;
+ }
#endif
- else
+ else {
return R_IMF_IMTYPE_JPEG90;
+ }
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index e59facd3c39..6cdeaf5e59b 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -170,10 +170,7 @@ Key *BKE_key_copy(Main *bmain, Key *key)
kb = kb->next;
}
- if (ID_IS_LINKED_DATABLOCK(key)) {
- BKE_id_expand_local(&keyn->id);
- BKE_id_lib_local_paths(bmain, key->id.lib, &keyn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &key->id, &keyn->id);
return keyn;
}
@@ -203,18 +200,6 @@ Key *BKE_key_copy_nolib(Key *key)
return keyn;
}
-void BKE_key_make_local(Main *bmain, Key *key)
-{
- /* Note that here for now we simply just make it local...
- * Sounds fishy behavior, but since skeys are not *real* IDs... */
-
- if (!ID_IS_LINKED_DATABLOCK(key)) {
- return;
- }
-
- id_clear_lib_data(bmain, &key->id);
-}
-
/* Sort shape keys and Ipo curves after a change. This assumes that at most
* one key was moved, which is a valid assumption for the places it's
* currently being called.
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 003b154a70b..e9d039ad480 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -135,13 +135,10 @@ Lamp *BKE_lamp_copy(Main *bmain, Lamp *la)
if (la->nodetree)
lan->nodetree = ntreeCopyTree(bmain, la->nodetree);
-
- lan->preview = BKE_previewimg_copy(la->preview);
- if (ID_IS_LINKED_DATABLOCK(la)) {
- BKE_id_expand_local(&lan->id);
- BKE_id_lib_local_paths(bmain, la->id.lib, &lan->id);
- }
+ BKE_previewimg_id_copy(&lan->id, &la->id);
+
+ BKE_id_copy_ensure_local(bmain, &la->id, &lan->id);
return lan;
}
@@ -172,34 +169,9 @@ Lamp *localize_lamp(Lamp *la)
return lan;
}
-void BKE_lamp_make_local(Main *bmain, Lamp *la)
+void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(la)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, la, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &la->id);
- BKE_id_expand_local(&la->id);
- }
- else {
- Lamp *la_new = BKE_lamp_copy(bmain, la);
-
- la_new->id.us = 0;
-
- BKE_libblock_remap(bmain, la, la_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &la->id, true, lib_local);
}
void BKE_lamp_free(Lamp *la)
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 67f49266efc..b0671f33094 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -297,10 +297,7 @@ Lattice *BKE_lattice_copy(Main *bmain, Lattice *lt)
ltn->editlatt = NULL;
- if (ID_IS_LINKED_DATABLOCK(lt)) {
- BKE_id_expand_local(&ltn->id);
- BKE_id_lib_local_paths(bmain, lt->id.lib, &ltn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &lt->id, &ltn->id);
return ltn;
}
@@ -330,37 +327,9 @@ void BKE_lattice_free(Lattice *lt)
}
-void BKE_lattice_make_local(Main *bmain, Lattice *lt)
+void BKE_lattice_make_local(Main *bmain, Lattice *lt, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(lt)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, lt, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &lt->id);
- if (lt->key) {
- BKE_key_make_local(bmain, lt->key);
- }
- BKE_id_expand_local(&lt->id);
- }
- else {
- Lattice *lt_new = BKE_lattice_copy(bmain, lt);
-
- lt_new->id.us = 0;
-
- BKE_libblock_remap(bmain, lt, lt_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &lt->id, true, lib_local);
}
typedef struct LatticeDeformData {
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 5fd929d6732..f19f1b45be6 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -76,12 +76,10 @@
#include "BLT_translation.h"
#include "RNA_access.h"
-#include "RNA_types.h"
#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
-#include "BKE_asset.h"
#include "BKE_bpath.h"
#include "BKE_brush.h"
#include "BKE_camera.h"
@@ -100,6 +98,7 @@
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
+#include "BKE_library_remap.h"
#include "BKE_linestyle.h"
#include "BKE_mesh.h"
#include "BKE_material.h"
@@ -110,6 +109,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
+#include "BKE_sound.h"
#include "BKE_speaker.h"
#include "BKE_scene.h"
#include "BKE_text.h"
@@ -134,6 +134,10 @@
* also note that the id _must_ have a library - campbell */
void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
{
+ if (lib->flag & LIBRARY_FLAG_VIRTUAL) {
+ return;
+ }
+
const char *bpath_user_data[2] = {bmain->name, lib->filepath};
BKE_bpath_traverse_id(bmain, id,
@@ -144,7 +148,7 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id)
void id_lib_extern(ID *id)
{
- if (id && ID_IS_LINKED_DATABLOCK(id)) {
+ if (id && ID_IS_LINKED(id)) {
BLI_assert(BKE_idcode_is_linkable(GS(id->name)));
if (id->tag & LIB_TAG_INDIRECT) {
id->tag -= LIB_TAG_INDIRECT;
@@ -271,90 +275,158 @@ void BKE_id_expand_local(ID *id)
BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0);
}
-/* calls the appropriate make_local method for the block, unless test. Returns true
- * if the block can be made local. */
-bool id_make_local(Main *bmain, ID *id, bool test)
+/**
+ * Ensure new (copied) ID is fully made local.
+ */
+void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id)
+{
+ if (ID_IS_LINKED(old_id)) {
+ BKE_id_expand_local(new_id);
+ BKE_id_lib_local_paths(bmain, old_id->lib, new_id);
+ }
+}
+
+/**
+ * Generic 'make local' function, works for most of datablock types...
+ */
+void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, const bool lib_local)
+{
+ bool is_local = false, is_lib = false;
+
+ /* - only lib users: do nothing (unless force_local is set)
+ * - only local users: set flag
+ * - mixed: make copy
+ * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
+ */
+
+ if (!ID_IS_LINKED(id)) {
+ return;
+ }
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+
+ if (lib_local || is_local) {
+ if (!is_lib) {
+ id_clear_lib_data_ex(bmain, id, id_in_mainlist);
+ BKE_id_expand_local(id);
+ }
+ else {
+ ID *id_new;
+
+ /* Should not fail in expected usecases, but id_copy does not copy Scene e.g. */
+ if (id_copy(bmain, id, &id_new, false)) {
+ id_new->us = 0;
+
+ if (!lib_local) {
+ BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ }
+ }
+ }
+ }
+
+}
+
+/**
+ * Calls the appropriate make_local method for the block, unless test is set.
+ *
+ * \param lib_local Special flag used when making a whole library's content local, it needs specific handling.
+ *
+ * \return true if the block can be made local.
+ */
+bool id_make_local(Main *bmain, ID *id, const bool test, const bool lib_local)
{
if (id->tag & LIB_TAG_INDIRECT)
return false;
switch (GS(id->name)) {
case ID_SCE:
- return false; /* not implemented */
+ /* Partially implemented (has no copy...). */
+ if (!test) BKE_scene_make_local(bmain, (Scene *)id, lib_local);
+ return true;
case ID_LI:
return false; /* can't be linked */
case ID_OB:
- if (!test) BKE_object_make_local(bmain, (Object *)id);
+ if (!test) BKE_object_make_local(bmain, (Object *)id, lib_local);
return true;
case ID_ME:
- if (!test) BKE_mesh_make_local(bmain, (Mesh *)id);
+ if (!test) BKE_mesh_make_local(bmain, (Mesh *)id, lib_local);
return true;
case ID_CU:
- if (!test) BKE_curve_make_local(bmain, (Curve *)id);
+ if (!test) BKE_curve_make_local(bmain, (Curve *)id, lib_local);
return true;
case ID_MB:
- if (!test) BKE_mball_make_local(bmain, (MetaBall *)id);
+ if (!test) BKE_mball_make_local(bmain, (MetaBall *)id, lib_local);
return true;
case ID_MA:
- if (!test) BKE_material_make_local(bmain, (Material *)id);
+ if (!test) BKE_material_make_local(bmain, (Material *)id, lib_local);
return true;
case ID_TE:
- if (!test) BKE_texture_make_local(bmain, (Tex *)id);
+ if (!test) BKE_texture_make_local(bmain, (Tex *)id, lib_local);
return true;
case ID_IM:
- if (!test) BKE_image_make_local(bmain, (Image *)id);
+ if (!test) BKE_image_make_local(bmain, (Image *)id, lib_local);
return true;
case ID_LT:
- if (!test) BKE_lattice_make_local(bmain, (Lattice *)id);
+ if (!test) BKE_lattice_make_local(bmain, (Lattice *)id, lib_local);
return true;
case ID_LA:
- if (!test) BKE_lamp_make_local(bmain, (Lamp *)id);
+ if (!test) BKE_lamp_make_local(bmain, (Lamp *)id, lib_local);
return true;
case ID_CA:
- if (!test) BKE_camera_make_local(bmain, (Camera *)id);
+ if (!test) BKE_camera_make_local(bmain, (Camera *)id, lib_local);
return true;
case ID_SPK:
- if (!test) BKE_speaker_make_local(bmain, (Speaker *)id);
+ if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, lib_local);
return true;
case ID_IP:
return false; /* deprecated */
case ID_KE:
- if (!test) BKE_key_make_local(bmain, (Key *)id);
- return true;
+ return false; /* can't be linked */
case ID_WO:
- if (!test) BKE_world_make_local(bmain, (World *)id);
+ if (!test) BKE_world_make_local(bmain, (World *)id, lib_local);
return true;
case ID_SCR:
return false; /* can't be linked */
case ID_VF:
- return false; /* not implemented */
+ /* Partially implemented (has no copy...). */
+ if (!test) BKE_vfont_make_local(bmain, (VFont *)id, lib_local);
+ return true;
case ID_TXT:
- return false; /* not implemented */
+ if (!test) BKE_text_make_local(bmain, (Text *)id, lib_local);
+ return true;
case ID_SO:
- return false; /* not implemented */
+ /* Partially implemented (has no copy...). */
+ if (!test) BKE_sound_make_local(bmain, (bSound *)id, lib_local);
+ return true;
case ID_GR:
- return false; /* not implemented */
+ if (!test) BKE_group_make_local(bmain, (Group *)id, lib_local);
+ return true;
case ID_AR:
- if (!test) BKE_armature_make_local(bmain, (bArmature *)id);
+ if (!test) BKE_armature_make_local(bmain, (bArmature *)id, lib_local);
return true;
case ID_AC:
- if (!test) BKE_action_make_local(bmain, (bAction *)id);
+ if (!test) BKE_action_make_local(bmain, (bAction *)id, lib_local);
return true;
case ID_NT:
- if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true);
+ if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true, lib_local);
return true;
case ID_BR:
- if (!test) BKE_brush_make_local(bmain, (Brush *)id);
+ if (!test) BKE_brush_make_local(bmain, (Brush *)id, lib_local);
return true;
case ID_PA:
- if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id);
+ if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id, lib_local);
return true;
case ID_WM:
return false; /* can't be linked */
case ID_GD:
- return false; /* not implemented */
+ if (!test) BKE_gpencil_make_local(bmain, (bGPdata *)id, lib_local);
+ return true;
+ case ID_MSK:
+ if (!test) BKE_mask_make_local(bmain, (Mask *)id, lib_local);
+ return true;
case ID_LS:
- return false; /* not implemented */
+ if (!test) BKE_linestyle_make_local(bmain, (FreestyleLineStyle *)id, lib_local);
+ return true;
}
return false;
@@ -643,7 +715,7 @@ void BKE_main_lib_objects_recalc_all(Main *bmain)
/* flag for full recalc */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
- if (ID_IS_LINKED_DATABLOCK(ob)) {
+ if (ID_IS_LINKED(ob)) {
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
}
@@ -1069,7 +1141,7 @@ static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **i
void BKE_libblock_relink(ID *id)
{
- if (ID_IS_LINKED_DATABLOCK(id))
+ if (ID_IS_LINKED(id))
return;
BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0);
@@ -1285,7 +1357,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
for (idtest = lb->first; idtest; idtest = idtest->next) {
/* if idtest is not a lib */
- if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) {
+ if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) { /* Virtual lib IDs are considered as local ones here. */
/* do not test alphabetic! */
/* optimized */
if (idtest->name[2] == name[0]) {
@@ -1426,7 +1498,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname)
bool result;
char name[MAX_ID_NAME - 2];
- /* if library, don't rename */
+ /* if real library, don't rename */
if (ID_IS_LINKED_DATABLOCK(id))
return false;
@@ -1472,9 +1544,10 @@ bool new_id(ListBase *lb, ID *id, const char *tname)
* Pull an ID out of a library (make it local). Only call this for IDs that
* don't have other library users.
*/
-void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist)
+void id_clear_lib_data_ex(Main *bmain, ID *id, const bool id_in_mainlist)
{
bNodeTree *ntree = NULL;
+ Key *key = NULL;
BKE_id_lib_local_paths(bmain, id->lib, id);
@@ -1485,13 +1558,14 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist)
if (id_in_mainlist)
new_id(which_libbase(bmain, GS(id->name)), id, NULL);
- /* internal bNodeTree blocks inside ID types below
- * also stores id->lib, make sure this stays in sync.
- */
- ntree = ntreeFromID(id);
+ /* Internal bNodeTree blocks inside datablocks also stores id->lib, make sure this stays in sync. */
+ if ((ntree = ntreeFromID(id))) {
+ id_clear_lib_data_ex(bmain, &ntree->id, false); /* Datablocks' nodetree is never in Main. */
+ }
- if (ntree) {
- ntreeMakeLocal(bmain, ntree, false);
+ /* Same goes for shapekeys. */
+ if ((key = BKE_key_from_id(id))) {
+ id_clear_lib_data_ex(bmain, &key->id, id_in_mainlist); /* sigh, why are keys in Main? */
}
if (GS(id->name) == ID_OB) {
@@ -1527,53 +1601,6 @@ void BKE_main_id_clear_newpoins(Main *bmain)
}
}
-static void lib_indirect_test_id(ID *id, const Library *lib)
-{
-#define LIBTAG(a) \
- if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0
-
- if (ID_IS_LINKED_DATABLOCK(id)) {
- /* datablocks that were indirectly related are now direct links
- * without this, appending data that has a link to other data will fail to write */
- if (lib && id->lib->parent == lib) {
- id_lib_extern(id);
- }
- return;
- }
-
- if (GS(id->name) == ID_OB) {
- Object *ob = (Object *)id;
- Mesh *me;
-
- int a;
-
-#if 0 /* XXX OLD ANIMSYS, NLASTRIPS ARE NO LONGER USED */
- /* XXX old animation system! -------------------------------------- */
- {
- bActionStrip *strip;
- for (strip = ob->nlastrips.first; strip; strip = strip->next) {
- LIBTAG(strip->object);
- LIBTAG(strip->act);
- LIBTAG(strip->ipo);
- }
- }
- /* XXX: new animation system needs something like this? */
-#endif
-
- for (a = 0; a < ob->totcol; a++) {
- LIBTAG(ob->mat[a]);
- }
-
- LIBTAG(ob->dup_group);
- LIBTAG(ob->proxy);
-
- me = ob->data;
- LIBTAG(me);
- }
-
-#undef LIBTAG
-}
-
/** Make linked datablocks local.
*
* \param bmain Almost certainly G.main.
@@ -1581,19 +1608,30 @@ static void lib_indirect_test_id(ID *id, const Library *lib)
* \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING.
* \param set_fake If true, set fake user on all localized datablocks (except group and objects ones).
*/
+/* XXX TODO This function should probably be reworked.
+ *
+ * Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether
+ * they were also indirectly used or not...
+ *
+ * Current version uses regular id_make_local callback, but this is not super-efficient since this ends up
+ * duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID).
+ *
+ * We could first check all IDs and detect those to be made local that are only used by other local or future-local
+ * datablocks, and directly tag those as local (instead of going through id_make_local) maybe...
+ *
+ * We'll probably need at some point a true dependency graph between datablocks, but for now this should work
+ * good enough (performances is not a critical point here anyway).
+ */
void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake)
{
ListBase *lbarray[MAX_LIBARRAY];
- ID *id, *idn;
+ ID *id, *id_next;
int a;
- a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- id = lbarray[a]->first;
-
- while (id) {
+ for (a = set_listbasepointers(bmain, lbarray); a--; ) {
+ for (id = lbarray[a]->first; id; id = id_next) {
id->newid = NULL;
- idn = id->next; /* id is possibly being inserted again */
+ id_next = id->next; /* id is possibly being inserted again */
/* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
* possible to tag data you don't want to be made local, used for
@@ -1605,14 +1643,8 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
{
if (lib == NULL || id->lib == lib) {
if (id->lib) {
- /* for Make Local > All we should be calling id_make_local,
- * but doing that breaks append (see #36003 and #36006), we
- * we should make it work with all datablocks and id.us==0 */
- id_clear_lib_data(bmain, id); /* sets 'id->tag' */
-
- /* why sort alphabetically here but not in
- * id_clear_lib_data() ? - campbell */
- id_sort_by_name(lbarray[a], id);
+ /* In this specific case, we do want to make ID local even if it has no local usage yet... */
+ id_make_local(bmain, id, false, true);
}
else {
id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
@@ -1626,231 +1658,40 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
}
}
}
-
- id = idn;
- }
- }
-
- a = set_listbasepointers(bmain, lbarray);
- while (a--) {
- for (id = lbarray[a]->first; id; id = id->next)
- lib_indirect_test_id(id, lib);
- }
-}
-
-/* Asset managing - TODO: we most likely want to turn this into a hashing at some point, could become a bit slow
- * when having huge assets (or many of them)... */
-void BKE_library_asset_repository_init(Library *lib, const AssetEngineType *aet, const char *repo_root)
-{
- BKE_library_asset_repository_free(lib);
- lib->asset_repository = MEM_mallocN(sizeof(*lib->asset_repository), __func__);
-
- BLI_strncpy(lib->asset_repository->asset_engine, aet->idname, sizeof(lib->asset_repository->asset_engine));
- lib->asset_repository->asset_engine_version = aet->version;
- BLI_strncpy(lib->asset_repository->root, repo_root, sizeof(lib->asset_repository->root));
-
- BLI_listbase_clear(&lib->asset_repository->assets);
-}
-
-void BKE_library_asset_repository_clear(Library *lib)
-{
- if (lib->asset_repository) {
- for (AssetRef *aref; (aref = BLI_pophead(&lib->asset_repository->assets)); ) {
- BLI_freelistN(&aref->id_list);
- MEM_freeN(aref);
- }
- }
-}
-
-void BKE_library_asset_repository_free(Library *lib)
-{
- if (lib->asset_repository) {
- BKE_library_asset_repository_clear(lib);
- MEM_freeN(lib->asset_repository);
- lib->asset_repository = NULL;
- }
-}
-
-AssetRef *BKE_library_asset_repository_asset_add(Library *lib, const void *idv)
-{
- const ID *id = idv;
- BLI_assert(id->uuid != NULL);
-
- AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv);
- if (!aref) {
- aref = MEM_callocN(sizeof(*aref), __func__);
- aref->uuid = *id->uuid;
- BKE_library_asset_repository_subdata_add(aref, idv);
- BLI_addtail(&lib->asset_repository->assets, aref);
- }
-
- return aref;
-}
-
-AssetRef *BKE_library_asset_repository_asset_find(Library *lib, const void *idv)
-{
- const ID *id = idv;
- BLI_assert(id->uuid != NULL);
-
- for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
- if (ASSETUUID_COMPARE(&aref->uuid, id->uuid)) {
-#ifndef NDEBUG
- LinkData *link = aref->id_list.first;
- BLI_assert(link && (link->data == idv));
-#endif
- return aref;
- }
- }
- return NULL;
-}
-
-void BKE_library_asset_repository_asset_remove(Library *lib, const void *idv)
-{
- AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv);
- BLI_remlink(&lib->asset_repository->assets, aref);
- BLI_freelistN(&aref->id_list);
- MEM_freeN(aref);
-}
-
-void BKE_library_asset_repository_subdata_add(AssetRef *aref, const void *idv)
-{
- if (BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data)) == NULL) {
- BLI_addtail(&aref->id_list, BLI_genericNodeN((void *)idv));
- }
-}
-
-void BKE_library_asset_repository_subdata_remove(AssetRef *aref, const void *idv)
-{
- LinkData *link = BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data));
- if (link) {
- BLI_freelinkN(&aref->id_list, link);
- }
-}
-
-void BKE_libraries_asset_subdata_remove(Main *bmain, const void *idv)
-{
- const ID *id = idv;
-
- if (id->lib == NULL) {
- return;
- }
-
- ListBase *lb = which_libbase(bmain, ID_LI);
- for (Library *lib = lb->first; lib; lib = lib->id.next) {
- if (lib->asset_repository) {
- for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
- BLI_freelinkN(&aref->id_list, BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data)));
- }
}
}
-}
-
-void BKE_libraries_asset_repositories_clear(Main *bmain)
-{
- ListBase *lb = which_libbase(bmain, ID_LI);
- for (Library *lib = lb->first; lib; lib = lib->id.next) {
- BKE_library_asset_repository_clear(lib);
- }
- BKE_main_id_tag_all(bmain, LIB_TAG_ASSET, false);
-}
-
-static int library_asset_dependencies_rebuild_cb(void *userdata, ID *id_self, ID **idp, int UNUSED(cd_flag))
-{
- if (!idp || !*idp) {
- return IDWALK_RET_NOP;
- }
- AssetRef *aref = userdata;
- ID *id = *idp;
-
- if (id->uuid) {
- return IDWALK_RET_STOP_RECURSION;
- }
-
- printf("%s (from %s)\n", id->name, id_self->name);
-
- BKE_library_asset_repository_subdata_add(aref, (const void *)id);
- id->tag |= LIB_TAG_ASSET;
- return IDWALK_RET_NOP;
-}
-
-static void library_asset_dependencies_rebuild(ID *asset)
-{
- Library *lib = asset->lib;
- BLI_assert(lib && lib->asset_repository);
-
- if (!(lib && lib->asset_repository)) {
- printf("asset: %s\n", asset->name);
- printf("lib: %p\n", lib);
- printf("lib: %s\n", lib->id.name);
- printf("lib: %s\n", lib->name);
- printf("lib: %p\n\n\n", lib->asset_repository);
- }
-
- asset->tag |= LIB_TAG_ASSET;
-
- AssetRef *aref = BKE_library_asset_repository_asset_add(lib, asset);
-
- BKE_library_foreach_ID_link(asset, library_asset_dependencies_rebuild_cb, aref, IDWALK_RECURSE);
-}
-
-void BKE_libraries_asset_repositories_rebuild(Main *bmain)
-{
- ListBase *lbarray[MAX_LIBARRAY];
- ID *id;
- int a;
-
- BKE_libraries_asset_repositories_clear(bmain);
-
- a = set_listbasepointers(bmain, lbarray);
- while (a--) {
+ /* We have to remap local usages of old (linked) ID to new (local) id in a second loop, as lbarray ordering is not
+ * enough to ensure us we did catch all dependencies (e.g. if making local a parent object before its child...).
+ * See T48907. */
+ for (a = set_listbasepointers(bmain, lbarray); a--; ) {
for (id = lbarray[a]->first; id; id = id->next) {
- if (id->uuid) {
- library_asset_dependencies_rebuild(id);
+ if (id->newid) {
+ BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
}
}
}
-}
-AssetRef *BKE_libraries_asset_repository_uuid_find(Main *bmain, const AssetUUID *uuid)
-{
- ListBase *lb = which_libbase(bmain, ID_LI);
- for (Library *lib = lb->first; lib; lib = lib->id.next) {
- for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
- if (ASSETUUID_COMPARE(&aref->uuid, uuid)) {
-#ifndef NDEBUG
- LinkData *link = aref->id_list.first;
- BLI_assert(link && ((ID *)link->data)->uuid && ASSETUUID_COMPARE(((ID *)link->data)->uuid, uuid));
-#endif
- return aref;
+ /* Third step: remove datablocks that have been copied to be localized and are no more used in the end...
+ * Note that we may have to loop more than once here, to tackle dependencies between linked objects... */
+ bool do_loop = true;
+ while (do_loop) {
+ do_loop = false;
+ for (a = set_listbasepointers(bmain, lbarray); a--; ) {
+ for (id = lbarray[a]->first; id; id = id_next) {
+ id_next = id->next;
+ if (id->newid) {
+ bool is_local = false, is_lib = false;
+
+ BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
+ if (!is_local && !is_lib) {
+ BKE_libblock_free(bmain, id);
+ do_loop = true;
+ }
+ }
}
}
}
- return NULL;
-}
-
-/** Find or add the 'virtual' library datablock matching this asset engine, used for non-blend-data assets. */
-Library *BKE_library_asset_virtual_ensure(Main *bmain, const AssetEngineType *aet)
-{
- Library *lib;
- ListBase *lb = which_libbase(bmain, ID_LI);
-
- for (lib = lb->first; lib; lib = lib->id.next) {
- if (!(lib->flag & LIBRARY_FLAG_VIRTUAL) || !lib->asset_repository) {
- continue;
- }
-
- if (STREQ(lib->asset_repository->asset_engine, aet->idname) &&
- lib->asset_repository->asset_engine_version == aet->version)
- {
- return lib;
- }
- }
-
- lib = BKE_libblock_alloc(bmain, ID_LI, "VirtualLib");
- BKE_library_asset_repository_init(lib, aet, "");
- lib->flag |= LIBRARY_FLAG_VIRTUAL;
- return lib;
}
diff --git a/source/blender/blenkernel/intern/library_asset.c b/source/blender/blenkernel/intern/library_asset.c
new file mode 100644
index 00000000000..9ee6a2e426e
--- /dev/null
+++ b/source/blender/blenkernel/intern/library_asset.c
@@ -0,0 +1,269 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015,2016 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Bastien Montagne.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/library_asset.c
+ * \ingroup bke
+ *
+ * Contains asset-related management of ID's and libraries.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "RNA_types.h"
+
+#include "BKE_asset_engine.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_main.h"
+
+
+/* Asset managing - TODO: we most likely want to turn this into a hashing at some point, could become a bit slow
+ * when having huge assets (or many of them)... */
+void BKE_library_asset_repository_init(Library *lib, const AssetEngineType *aet, const char *repo_root)
+{
+ BKE_library_asset_repository_free(lib);
+ lib->asset_repository = MEM_mallocN(sizeof(*lib->asset_repository), __func__);
+
+ BLI_strncpy(lib->asset_repository->asset_engine, aet->idname, sizeof(lib->asset_repository->asset_engine));
+ lib->asset_repository->asset_engine_version = aet->version;
+ BLI_strncpy(lib->asset_repository->root, repo_root, sizeof(lib->asset_repository->root));
+
+ BLI_listbase_clear(&lib->asset_repository->assets);
+}
+
+void BKE_library_asset_repository_clear(Library *lib)
+{
+ if (lib->asset_repository) {
+ for (AssetRef *aref; (aref = BLI_pophead(&lib->asset_repository->assets)); ) {
+ BLI_freelistN(&aref->id_list);
+ MEM_freeN(aref);
+ }
+ }
+}
+
+void BKE_library_asset_repository_free(Library *lib)
+{
+ if (lib->asset_repository) {
+ BKE_library_asset_repository_clear(lib);
+ MEM_freeN(lib->asset_repository);
+ lib->asset_repository = NULL;
+ }
+}
+
+AssetRef *BKE_library_asset_repository_asset_add(Library *lib, const void *idv)
+{
+ const ID *id = idv;
+ BLI_assert(id->uuid != NULL);
+
+ AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv);
+ if (!aref) {
+ aref = MEM_callocN(sizeof(*aref), __func__);
+ aref->uuid = *id->uuid;
+ BKE_library_asset_repository_subdata_add(aref, idv);
+ BLI_addtail(&lib->asset_repository->assets, aref);
+ }
+
+ return aref;
+}
+
+AssetRef *BKE_library_asset_repository_asset_find(Library *lib, const void *idv)
+{
+ const ID *id = idv;
+ BLI_assert(id->uuid != NULL);
+
+ for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
+ if (ASSETUUID_COMPARE(&aref->uuid, id->uuid)) {
+#ifndef NDEBUG
+ LinkData *link = aref->id_list.first;
+ BLI_assert(link && (link->data == idv));
+#endif
+ return aref;
+ }
+ }
+ return NULL;
+}
+
+void BKE_library_asset_repository_asset_remove(Library *lib, const void *idv)
+{
+ AssetRef *aref = BKE_library_asset_repository_asset_find(lib, idv);
+ BLI_remlink(&lib->asset_repository->assets, aref);
+ BLI_freelistN(&aref->id_list);
+ MEM_freeN(aref);
+}
+
+void BKE_library_asset_repository_subdata_add(AssetRef *aref, const void *idv)
+{
+ if (BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data)) == NULL) {
+ BLI_addtail(&aref->id_list, BLI_genericNodeN((void *)idv));
+ }
+}
+
+void BKE_library_asset_repository_subdata_remove(AssetRef *aref, const void *idv)
+{
+ LinkData *link = BLI_findptr(&aref->id_list, idv, offsetof(LinkData, data));
+ if (link) {
+ BLI_freelinkN(&aref->id_list, link);
+ }
+}
+
+void BKE_libraries_asset_subdata_remove(Main *bmain, const void *idv)
+{
+ const ID *id = idv;
+
+ if (id->lib == NULL) {
+ return;
+ }
+
+ ListBase *lb = &bmain->library;
+ for (Library *lib = lb->first; lib; lib = lib->id.next) {
+ if (lib->asset_repository) {
+ for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
+ LinkData *subdata = aref->id_list.first;
+ /* Skip first one, it's main asset, not subdata! */
+ for (subdata = subdata->next; subdata; subdata = subdata->next) {
+ if (subdata->data == idv) {
+ BLI_freelinkN(&aref->id_list, subdata);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void BKE_libraries_asset_repositories_clear(Main *bmain)
+{
+ ListBase *lb = which_libbase(bmain, ID_LI);
+ for (Library *lib = lb->first; lib; lib = lib->id.next) {
+ BKE_library_asset_repository_clear(lib);
+ }
+ BKE_main_id_tag_all(bmain, LIB_TAG_ASSET, false);
+}
+
+static int library_asset_dependencies_rebuild_cb(void *userdata, ID *id_self, ID **idp, int UNUSED(cd_flag))
+{
+ if (!idp || !*idp) {
+ return IDWALK_RET_NOP;
+ }
+
+ AssetRef *aref = userdata;
+ ID *id = *idp;
+
+ if (id->uuid) {
+ return IDWALK_RET_STOP_RECURSION;
+ }
+
+ printf("%s (from %s)\n", id->name, id_self->name);
+
+ BKE_library_asset_repository_subdata_add(aref, (const void *)id);
+ id->tag |= LIB_TAG_ASSET;
+ return IDWALK_RET_NOP;
+}
+
+static void library_asset_dependencies_rebuild(ID *asset)
+{
+ Library *lib = asset->lib;
+ BLI_assert(lib && lib->asset_repository);
+
+ if (!(lib && lib->asset_repository)) {
+ printf("asset: %s\n", asset->name);
+ printf("lib: %p\n", lib);
+ printf("lib: %s\n", lib->id.name);
+ printf("lib: %s\n", lib->name);
+ printf("lib: %p\n\n\n", lib->asset_repository);
+ }
+
+ asset->tag |= LIB_TAG_ASSET;
+
+ AssetRef *aref = BKE_library_asset_repository_asset_add(lib, asset);
+
+ BKE_library_foreach_ID_link(asset, library_asset_dependencies_rebuild_cb, aref, IDWALK_RECURSE);
+}
+
+void BKE_libraries_asset_repositories_rebuild(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ BKE_libraries_asset_repositories_clear(bmain);
+
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ for (id = lbarray[a]->first; id; id = id->next) {
+ if (id->uuid) {
+ library_asset_dependencies_rebuild(id);
+ }
+ }
+ }
+}
+
+AssetRef *BKE_libraries_asset_repository_uuid_find(Main *bmain, const AssetUUID *uuid)
+{
+ ListBase *lb = which_libbase(bmain, ID_LI);
+ for (Library *lib = lb->first; lib; lib = lib->id.next) {
+ for (AssetRef *aref = lib->asset_repository->assets.first; aref; aref = aref->next) {
+ if (ASSETUUID_COMPARE(&aref->uuid, uuid)) {
+#ifndef NDEBUG
+ LinkData *link = aref->id_list.first;
+ BLI_assert(link && ((ID *)link->data)->uuid && ASSETUUID_COMPARE(((ID *)link->data)->uuid, uuid));
+#endif
+ return aref;
+ }
+ }
+ }
+ return NULL;
+}
+
+/** Find or add the 'virtual' library datablock matching this asset engine, used for non-blend-data assets. */
+Library *BKE_library_asset_virtual_ensure(Main *bmain, const AssetEngineType *aet)
+{
+ Library *lib;
+ ListBase *lb = which_libbase(bmain, ID_LI);
+
+ for (lib = lb->first; lib; lib = lib->id.next) {
+ if (!(lib->flag & LIBRARY_FLAG_VIRTUAL) || !lib->asset_repository) {
+ continue;
+ }
+
+ if (STREQ(lib->asset_repository->asset_engine, aet->idname) &&
+ lib->asset_repository->asset_engine_version == aet->version)
+ {
+ return lib;
+ }
+ }
+
+ lib = BKE_libblock_alloc(bmain, ID_LI, "VirtualLib");
+ BKE_library_asset_repository_init(lib, aet, "");
+ lib->flag |= LIBRARY_FLAG_VIRTUAL;
+ return lib;
+}
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index f86f5fa01ec..a33c63c07af 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -298,7 +298,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
do {
data.self_id = id;
- data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0;
+ data.cd_flag = ID_IS_LINKED(id) ? IDWALK_INDIRECT_USAGE : 0;
AnimData *adt = BKE_animdata_from_id(id);
if (adt) {
@@ -442,7 +442,16 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
/* object->proxy is refcounted, but not object->proxy_group... *sigh* */
CALLBACK_INVOKE(object->proxy, IDWALK_USER);
CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP);
+
+ /* Special case!
+ * Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage
+ * if proxy object is linked... Twisted. */
+ if (object->proxy_from) {
+ data.cd_flag = ID_IS_LINKED(object->proxy_from) ? IDWALK_INDIRECT_USAGE : 0;
+ }
CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP);
+ data.cd_flag = data_cd_flag;
+
CALLBACK_INVOKE(object->poselib, IDWALK_USER);
data.cd_flag |= proxy_cd_flag;
@@ -856,9 +865,10 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag)
/**
* Say whether given \a id_type_owner can use (in any way) a datablock of \a id_type_used.
+ *
+ * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above, quite useful to reduce
+ * useless iterations in some cases.
*/
-/* This is a 'simplified' abstract version of BKE_library_foreach_ID_link() above, quite useful to reduce
- * useless ietrations in some cases. */
bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used)
{
if (id_type_used == ID_AC) {
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index b158b3f968b..9ac795ddf44 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -296,6 +296,9 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data)
if (ob->pose && (!old_id || ob->data == old_id)) {
BLI_assert(ob->type == OB_ARMATURE);
ob->pose->flag |= POSE_RECALC;
+ /* We need to clear pose bone pointers immediately, things like undo writefile may be called
+ * before pose is actually recomputed, can lead to segfault... */
+ BKE_pose_clear_pointers(ob->pose);
}
}
break;
@@ -641,6 +644,7 @@ void BKE_libblock_relink_ex(
libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL);
}
}
+ break;
}
case ID_OB:
if (new_id) { /* Only affects us in case obdata was relinked (changed). */
@@ -682,6 +686,10 @@ void BKE_libblock_free_data(Main *bmain, ID *id)
MEM_freeN(id->properties);
}
+ if (id->uuid) {
+ MEM_freeN(id->uuid);
+ }
+
/* this ID may be a driver target! */
BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id);
}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index c4a0d0074fb..430935a5fad 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -218,14 +218,16 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l
for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next)
BKE_linestyle_geometry_modifier_copy(new_linestyle, m);
- if (ID_IS_LINKED_DATABLOCK(linestyle)) {
- BKE_id_expand_local(&new_linestyle->id);
- BKE_id_lib_local_paths(bmain, linestyle->id.lib, &new_linestyle->id);
- }
+ BKE_id_copy_ensure_local(bmain, &linestyle->id, &new_linestyle->id);
return new_linestyle;
}
+void BKE_linestyle_make_local(struct Main *bmain, FreestyleLineStyle *linestyle, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &linestyle->id, true, lib_local);
+}
+
FreestyleLineStyle *BKE_linestyle_active_from_scene(Scene *scene)
{
SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 9e070bbef22..21023d9f53c 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -853,14 +853,16 @@ Mask *BKE_mask_copy(Main *bmain, Mask *mask)
/* enable fake user by default */
id_fake_user_set(&mask->id);
- if (ID_IS_LINKED_DATABLOCK(mask)) {
- BKE_id_expand_local(&mask_new->id);
- BKE_id_lib_local_paths(bmain, mask->id.lib, &mask_new->id);
- }
+ BKE_id_copy_ensure_local(bmain, &mask->id, &mask_new->id);
return mask_new;
}
+void BKE_mask_make_local(Main *bmain, Mask *mask, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &mask->id, true, lib_local);
+}
+
void BKE_mask_point_free(MaskSplinePoint *point)
{
if (point->uw)
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 17811893c03..0be32c9b84c 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -243,14 +243,11 @@ Material *BKE_material_copy(Main *bmain, Material *ma)
man->nodetree = ntreeCopyTree(bmain, ma->nodetree);
}
- man->preview = BKE_previewimg_copy(ma->preview);
+ BKE_previewimg_id_copy(&man->id, &ma->id);
BLI_listbase_clear(&man->gpumaterial);
- if (ID_IS_LINKED_DATABLOCK(ma)) {
- BKE_id_expand_local(&man->id);
- BKE_id_lib_local_paths(bmain, ma->id.lib, &man->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ma->id, &man->id);
return man;
}
@@ -285,34 +282,9 @@ Material *localize_material(Material *ma)
return man;
}
-void BKE_material_make_local(Main *bmain, Material *ma)
+void BKE_material_make_local(Main *bmain, Material *ma, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(ma)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, ma, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &ma->id);
- BKE_id_expand_local(&ma->id);
- }
- else {
- Material *ma_new = BKE_material_copy(bmain, ma);
-
- ma_new->id.us = 0;
-
- BKE_libblock_remap(bmain, ma, ma_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &ma->id, true, lib_local);
}
Material ***give_matarar(Object *ob)
@@ -569,18 +541,6 @@ Material *give_current_material(Object *ob, short act)
return ma;
}
-ID *material_from(Object *ob, short act)
-{
-
- if (ob == NULL) return NULL;
-
- if (ob->totcol == 0) return ob->data;
- if (act == 0) act = 1;
-
- if (ob->matbits[act - 1]) return (ID *)ob;
- else return ob->data;
-}
-
Material *give_node_material(Material *ma)
{
if (ma && ma->use_nodes && ma->nodetree) {
@@ -886,7 +846,11 @@ void assign_matarar(struct Object *ob, struct Material ***matar, short totcol)
int actcol_orig = ob->actcol;
short i;
- while (object_remove_material_slot(ob)) {}
+ while ((ob->totcol > totcol) &&
+ BKE_object_material_slot_remove(ob))
+ {
+ /* pass */
+ }
/* now we have the right number of slots */
for (i = 0; i < totcol; i++)
@@ -899,7 +863,7 @@ void assign_matarar(struct Object *ob, struct Material ***matar, short totcol)
}
-short find_material_index(Object *ob, Material *ma)
+short BKE_object_material_slot_find_index(Object *ob, Material *ma)
{
Material ***matarar;
short a, *totcolp;
@@ -919,7 +883,7 @@ short find_material_index(Object *ob, Material *ma)
return 0;
}
-bool object_add_material_slot(Object *ob)
+bool BKE_object_material_slot_add(Object *ob)
{
if (ob == NULL) return false;
if (ob->totcol >= MAXMAT) return false;
@@ -1201,7 +1165,7 @@ void material_drivers_update(Scene *scene, Material *ma, float ctime)
ma->id.tag &= ~LIB_TAG_DOIT;
}
-bool object_remove_material_slot(Object *ob)
+bool BKE_object_material_slot_remove(Object *ob)
{
Material *mao, ***matarar;
Object *obt;
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 9a0a6e3540c..8d024ea9aa5 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -119,42 +119,14 @@ MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb)
mbn->editelems = NULL;
mbn->lastelem = NULL;
- if (ID_IS_LINKED_DATABLOCK(mb)) {
- BKE_id_expand_local(&mbn->id);
- BKE_id_lib_local_paths(bmain, mb->id.lib, &mbn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &mb->id, &mbn->id);
return mbn;
}
-void BKE_mball_make_local(Main *bmain, MetaBall *mb)
+void BKE_mball_make_local(Main *bmain, MetaBall *mb, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(mb)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, mb, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &mb->id);
- BKE_id_expand_local(&mb->id);
- }
- else {
- MetaBall *mb_new = BKE_mball_copy(bmain, mb);
-
- mb_new->id.us = 0;
-
- BKE_libblock_remap(bmain, mb, mb_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &mb->id, true, lib_local);
}
/* most simple meta-element adding function
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 787b9905734..733e9030056 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -31,6 +31,7 @@
#include "DNA_scene_types.h"
#include "DNA_material_types.h"
+#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
@@ -530,10 +531,7 @@ Mesh *BKE_mesh_copy(Main *bmain, Mesh *me)
men->key->from = (ID *)men;
}
- if (ID_IS_LINKED_DATABLOCK(me)) {
- BKE_id_expand_local(&men->id);
- BKE_id_lib_local_paths(bmain, me->id.lib, &men->id);
- }
+ BKE_id_copy_ensure_local(bmain, &me->id, &men->id);
return men;
}
@@ -555,37 +553,9 @@ BMesh *BKE_mesh_to_bmesh(
return bm;
}
-void BKE_mesh_make_local(Main *bmain, Mesh *me)
+void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(me)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, me, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &me->id);
- if (me->key) {
- BKE_key_make_local(bmain, me->key);
- }
- BKE_id_expand_local(&me->id);
- }
- else {
- Mesh *me_new = BKE_mesh_copy(bmain, me);
-
- me_new->id.us = 0;
-
- BKE_libblock_remap(bmain, me, me_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &me->id, true, lib_local);
}
bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int loop_index, const int face_index,
@@ -2227,7 +2197,6 @@ Mesh *BKE_mesh_new_from_object(
{
Mesh *tmpmesh;
Curve *tmpcu = NULL, *copycu;
- Object *tmpobj = NULL;
int render = settings == eModifierMode_Render, i;
int cage = !apply_modifiers;
@@ -2242,7 +2211,7 @@ Mesh *BKE_mesh_new_from_object(
int uv_from_orco;
/* copies object and modifiers (but not the data) */
- tmpobj = BKE_object_copy_ex(bmain, ob, true);
+ Object *tmpobj = BKE_object_copy_ex(bmain, ob, true);
tmpcu = (Curve *)tmpobj->data;
id_us_min(&tmpcu->id);
@@ -2398,23 +2367,25 @@ Mesh *BKE_mesh_new_from_object(
}
break;
-#if 0
- /* Crashes when assigning the new material, not sure why */
case OB_MBALL:
- tmpmb = (MetaBall *)ob->data;
+ {
+ MetaBall *tmpmb = (MetaBall *)ob->data;
+ tmpmesh->mat = MEM_dupallocN(tmpmb->mat);
tmpmesh->totcol = tmpmb->totcol;
/* free old material list (if it exists) and adjust user counts */
if (tmpmb->mat) {
for (i = tmpmb->totcol; i-- > 0; ) {
- tmpmesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */
+ /* are we an object material or data based? */
+ tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpmb->mat[i];
+
if (tmpmesh->mat[i]) {
- id_us_plus(&tmpmb->mat[i]->id);
+ id_us_plus(&tmpmesh->mat[i]->id);
}
}
}
break;
-#endif
+ }
case OB_MESH:
if (!cage) {
@@ -2442,9 +2413,6 @@ Mesh *BKE_mesh_new_from_object(
BKE_mesh_tessface_ensure(tmpmesh);
}
- /* make sure materials get updated in object */
- test_object_materials(tmpobj ? tmpobj : ob, &tmpmesh->id);
-
return tmpmesh;
}
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index a472b6e5bc1..8562988b5e1 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -393,6 +393,60 @@ void BKE_mesh_vert_edge_vert_map_create(
}
/**
+ * Generates a map where the key is the edge and the value is a list of loops that use that edge.
+ * Loops indices of a same poly are contiguous and in winding order.
+ * The lists are allocated from one memory pool.
+ */
+void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map, int **r_mem,
+ const MEdge *UNUSED(medge), const int totedge,
+ const MPoly *mpoly, const int totpoly,
+ const MLoop *mloop, const int totloop)
+{
+ MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
+ int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop * 2, "edge-poly map mem");
+ int *index_step;
+ const MPoly *mp;
+ int i;
+
+ /* count face users */
+ for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
+ const MLoop *ml;
+ int j = mp->totloop;
+ for (ml = &mloop[mp->loopstart]; j--; ml++) {
+ map[ml->e].count += 2;
+ }
+ }
+
+ /* create offsets */
+ index_step = indices;
+ for (i = 0; i < totedge; i++) {
+ map[i].indices = index_step;
+ index_step += map[i].count;
+
+ /* re-count, using this as an index below */
+ map[i].count = 0;
+ }
+
+ /* assign loop-edge users */
+ for (i = 0, mp = mpoly; i < totpoly; mp++, i++) {
+ const MLoop *ml;
+ MeshElemMap *map_ele;
+ const int max_loop = mp->loopstart + mp->totloop;
+ int j = mp->loopstart;
+ for (ml = &mloop[j]; j < max_loop; j++, ml++) {
+ map_ele = &map[ml->e];
+ map_ele->indices[map_ele->count++] = j;
+ map_ele->indices[map_ele->count++] = j + 1;
+ }
+ /* last edge/loop of poly, must point back to first loop! */
+ map_ele->indices[map_ele->count - 1] = mp->loopstart;
+ }
+
+ *r_map = map;
+ *r_mem = indices;
+}
+
+/**
* Generates a map where the key is the edge and the value is a list of polygons that use that edge.
* The lists are allocated from one memory pool.
*/
@@ -539,12 +593,12 @@ void BKE_mesh_origindex_map_create_looptri(
*/
typedef bool (*MeshRemap_CheckIslandBoundary)(
const struct MPoly *mpoly, const struct MLoop *mloop, const struct MEdge *medge,
- const int nbr_egde_users);
+ const int nbr_egde_users, void *user_data);
static void poly_edge_loop_islands_calc(
const MEdge *medge, const int totedge, const MPoly *mpoly, const int totpoly,
const MLoop *mloop, const int totloop, MeshElemMap *edge_poly_map,
- const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check,
+ const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check, void *edge_boundary_check_data,
int **r_poly_groups, int *r_totgroup, BLI_bitmap **r_edge_borders, int *r_totedgeborder)
{
int *poly_groups;
@@ -626,7 +680,7 @@ static void poly_edge_loop_islands_calc(
const MeshElemMap *map_ele = &edge_poly_map[me_idx];
const int *p = map_ele->indices;
int i = map_ele->count;
- if (!edge_boundary_check(mp, ml, me, i)) {
+ if (!edge_boundary_check(mp, ml, me, i, edge_boundary_check_data)) {
for (; i--; p++) {
/* if we meet other non initialized its a bug */
BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id));
@@ -718,7 +772,7 @@ static void poly_edge_loop_islands_calc(
}
static bool poly_is_island_boundary_smooth_cb(
- const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users)
+ const MPoly *mp, const MLoop *UNUSED(ml), const MEdge *me, const int nbr_egde_users, void *UNUSED(user_data))
{
/* Edge is sharp if its poly is sharp, or edge itself is sharp, or edge is not used by exactly two polygons. */
return (!(mp->flag & ME_SMOOTH) || (me->flag & ME_SHARP) || (nbr_egde_users != 2));
@@ -741,7 +795,7 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge,
poly_edge_loop_islands_calc(
medge, totedge, mpoly, totpoly, mloop, totloop, NULL, use_bitflags,
- poly_is_island_boundary_smooth_cb, &poly_groups, r_totgroup, NULL, NULL);
+ poly_is_island_boundary_smooth_cb, NULL, &poly_groups, r_totgroup, NULL, NULL);
return poly_groups;
}
@@ -848,28 +902,60 @@ void BKE_mesh_loop_islands_add(
* Would make things much more complex though, and each UVMap would then need its own mesh mapping,
* not sure we want that at all!
*/
+typedef struct MeshCheckIslandBoundaryUv {
+ const MLoop *loops;
+ const MLoopUV *luvs;
+ const MeshElemMap *edge_loop_map;
+} MeshCheckIslandBoundaryUv;
+
static bool mesh_check_island_boundary_uv(
- const MPoly *UNUSED(mp), const MLoop *UNUSED(ml), const MEdge *me, const int UNUSED(nbr_egde_users))
+ const MPoly *UNUSED(mp), const MLoop *ml, const MEdge *me,
+ const int UNUSED(nbr_egde_users), void *user_data)
{
- /* Edge is UV boundary if tagged as seam. */
- return (me->flag & ME_SEAM) != 0;
+ if (user_data) {
+ const MeshCheckIslandBoundaryUv *data = user_data;
+ const MLoop *loops = data->loops;
+ const MLoopUV *luvs = data->luvs;
+ const MeshElemMap *edge_to_loops = &data->edge_loop_map[ml->e];
+
+ BLI_assert(edge_to_loops->count >= 2 && (edge_to_loops->count % 2) == 0);
+
+ const unsigned int v1 = loops[edge_to_loops->indices[0]].v;
+ const unsigned int v2 = loops[edge_to_loops->indices[1]].v;
+ const float *uvco_v1 = luvs[edge_to_loops->indices[0]].uv;
+ const float *uvco_v2 = luvs[edge_to_loops->indices[1]].uv;
+ for (int i = 2; i < edge_to_loops->count; i += 2) {
+ if (loops[edge_to_loops->indices[i]].v == v1) {
+ if (!equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i]].uv) ||
+ !equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i + 1]].uv))
+ {
+ return true;
+ }
+ }
+ else {
+ BLI_assert(loops[edge_to_loops->indices[i]].v == v2);
+ UNUSED_VARS_NDEBUG(v2);
+ if (!equals_v2v2(uvco_v2, luvs[edge_to_loops->indices[i]].uv) ||
+ !equals_v2v2(uvco_v1, luvs[edge_to_loops->indices[i + 1]].uv))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ else {
+ /* Edge is UV boundary if tagged as seam. */
+ return (me->flag & ME_SEAM) != 0;
+ }
}
-/**
- * Calculate UV islands.
- *
- * \note Currently we only consider edges tagges as seams as UV boundaries. This has the advantages of simplicity,
- * and being valid/common to all UV maps. However, it means actual UV islands whithout matching UV seams
- * will not be handled correctly...
- *
- * \note All this could be optimized...
- * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do...
- */
-bool BKE_mesh_calc_islands_loop_poly_uv(
+static bool mesh_calc_islands_loop_poly_uv(
MVert *UNUSED(verts), const int UNUSED(totvert),
MEdge *edges, const int totedge,
MPoly *polys, const int totpoly,
MLoop *loops, const int totloop,
+ const MLoopUV *luvs,
MeshIslandStore *r_island_store)
{
int *poly_groups = NULL;
@@ -879,6 +965,11 @@ bool BKE_mesh_calc_islands_loop_poly_uv(
MeshElemMap *edge_poly_map;
int *edge_poly_mem;
+ MeshElemMap *edge_loop_map;
+ int *edge_loop_mem;
+
+ MeshCheckIslandBoundaryUv edge_boundary_check_data;
+
int *poly_indices;
int *loop_indices;
int num_pidx, num_lidx;
@@ -899,9 +990,18 @@ bool BKE_mesh_calc_islands_loop_poly_uv(
BKE_mesh_edge_poly_map_create(&edge_poly_map, &edge_poly_mem,
edges, totedge, polys, totpoly, loops, totloop);
+ if (luvs) {
+ BKE_mesh_edge_loop_map_create(&edge_loop_map, &edge_loop_mem,
+ edges, totedge, polys, totpoly, loops, totloop);
+ edge_boundary_check_data.loops = loops;
+ edge_boundary_check_data.luvs = luvs;
+ edge_boundary_check_data.edge_loop_map = edge_loop_map;
+ }
+
poly_edge_loop_islands_calc(
- edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false,
- mesh_check_island_boundary_uv, &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders);
+ edges, totedge, polys, totpoly, loops, totloop, edge_poly_map, false,
+ mesh_check_island_boundary_uv, luvs ? &edge_boundary_check_data : NULL,
+ &poly_groups, &num_poly_groups, &edge_borders, &num_edge_borders);
if (!num_poly_groups) {
/* Should never happen... */
@@ -958,6 +1058,11 @@ bool BKE_mesh_calc_islands_loop_poly_uv(
MEM_freeN(edge_poly_map);
MEM_freeN(edge_poly_mem);
+ if (luvs) {
+ MEM_freeN(edge_loop_map);
+ MEM_freeN(edge_loop_mem);
+ }
+
MEM_freeN(poly_indices);
MEM_freeN(loop_indices);
MEM_freeN(poly_groups);
@@ -973,4 +1078,42 @@ bool BKE_mesh_calc_islands_loop_poly_uv(
return true;
}
+/**
+ * Calculate 'generic' UV islands, i.e. based only on actual geometry data (edge seams), not some UV layers coordinates.
+ */
+bool BKE_mesh_calc_islands_loop_poly_edgeseam(
+ MVert *verts, const int totvert,
+ MEdge *edges, const int totedge,
+ MPoly *polys, const int totpoly,
+ MLoop *loops, const int totloop,
+ MeshIslandStore *r_island_store)
+{
+ return mesh_calc_islands_loop_poly_uv(
+ verts, totvert, edges, totedge, polys, totpoly, loops, totloop, NULL, r_island_store);
+}
+
+/**
+ * Calculate UV islands.
+ *
+ * \note If no MLoopUV layer is passed, we only consider edges tagged as seams as UV boundaries.
+ * This has the advantages of simplicity, and being valid/common to all UV maps.
+ * However, it means actual UV islands whithout matching UV seams will not be handled correctly...
+ * If a valid UV layer is passed as \a luvs parameter, UV coordinates are also used to detect islands boundaries.
+ *
+ * \note All this could be optimized...
+ * Not sure it would be worth the more complex code, though, those loops are supposed to be really quick to do...
+ */
+bool BKE_mesh_calc_islands_loop_poly_uvmap(
+ MVert *verts, const int totvert,
+ MEdge *edges, const int totedge,
+ MPoly *polys, const int totpoly,
+ MLoop *loops, const int totloop,
+ const MLoopUV *luvs,
+ MeshIslandStore *r_island_store)
+{
+ BLI_assert(luvs != NULL);
+ return mesh_calc_islands_loop_poly_uv(
+ verts, totvert, edges, totedge, polys, totpoly, loops, totloop, luvs, r_island_store);
+}
+
/** \} */
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 41e4c21d814..349e99bab61 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -707,7 +707,7 @@ void test_object_modifiers(Object *ob)
*/
const char *modifier_path_relbase(Object *ob)
{
- if (G.relbase_valid || ID_IS_LINKED_DATABLOCK(ob)) {
+ if (G.relbase_valid || ID_IS_LINKED(ob)) {
return ID_BLEND_PATH(G.main, &ob->id);
}
else {
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 296a00388c4..fad7b3b098e 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -1211,7 +1211,6 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski
}
else {
newtree = BKE_libblock_copy_nolib(&ntree->id, true);
- newtree->id.lib = NULL; /* same as owning datablock id.lib */
}
id_us_plus((ID *)newtree->gpd);
@@ -1291,10 +1290,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski
/* node tree will generate its own interface type */
newtree->interface_type = NULL;
- if (ID_IS_LINKED_DATABLOCK(ntree)) {
- BKE_id_expand_local(&newtree->id);
- BKE_id_lib_local_paths(bmain, ntree->id.lib, &newtree->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ntree->id, &newtree->id);
return newtree;
}
@@ -1951,34 +1947,9 @@ bNodeTree *ntreeFromID(ID *id)
}
}
-void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist)
+void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist, const bool lib_local)
{
- bool is_lib = false, is_local = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(ntree)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, ntree, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist);
- BKE_id_expand_local(&ntree->id);
- }
- else {
- bNodeTree *ntree_new = ntreeCopyTree(bmain, ntree);
-
- ntree_new->id.us = 0;
-
- BKE_libblock_remap(bmain, ntree, ntree_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &ntree->id, id_in_mainlist, lib_local);
}
int ntreeNodeExists(bNodeTree *ntree, bNode *testnode)
@@ -2681,7 +2652,7 @@ void BKE_node_clipboard_add_node(bNode *node)
node_info->id = node->id;
if (node->id) {
BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name));
- if (ID_IS_LINKED_DATABLOCK(node->id)) {
+ if (ID_IS_LINKED_DATABLOCK(node->id)) { /* Don't want virtual libraries here... */
BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name));
}
else {
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 30a193506a6..4bf92c30c6a 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1169,10 +1169,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
/* Copy runtime surve data. */
obn->curve_cache = NULL;
- if (ID_IS_LINKED_DATABLOCK(ob)) {
- BKE_id_expand_local(&obn->id);
- BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ob->id, &obn->id);
/* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */
obn->preview = NULL;
@@ -1186,22 +1183,23 @@ Object *BKE_object_copy(Main *bmain, Object *ob)
return BKE_object_copy_ex(bmain, ob, false);
}
-void BKE_object_make_local(Main *bmain, Object *ob)
+void BKE_object_make_local(Main *bmain, Object *ob, const bool lib_local)
{
bool is_local = false, is_lib = false;
- /* - only lib users: do nothing
+ /* - only lib users: do nothing (unless force_local is set)
* - only local users: set flag
* - mixed: make copy
+ * In case we make a whole lib's content local, we always want to localize, and we skip remapping (done later).
*/
- if (!ID_IS_LINKED_DATABLOCK(ob)) {
+ if (!ID_IS_LINKED(ob)) {
return;
}
BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib);
- if (is_local) {
+ if (lib_local || is_local) {
if (!is_lib) {
id_clear_lib_data(bmain, &ob->id);
BKE_id_expand_local(&ob->id);
@@ -1212,7 +1210,9 @@ void BKE_object_make_local(Main *bmain, Object *ob)
ob_new->id.us = 0;
ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL;
- BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ if (!lib_local) {
+ BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE);
+ }
}
}
}
@@ -1220,15 +1220,15 @@ void BKE_object_make_local(Main *bmain, Object *ob)
/* Returns true if the Object is from an external blend file (libdata) */
bool BKE_object_is_libdata(Object *ob)
{
- return (ob && ID_IS_LINKED_DATABLOCK(ob));
+ return (ob && ID_IS_LINKED(ob));
}
/* Returns true if the Object data is from an external blend file (libdata) */
bool BKE_object_obdata_is_libdata(Object *ob)
{
/* Linked objects with local obdata are forbidden! */
- BLI_assert(!ob || !ob->data || (ID_IS_LINKED_DATABLOCK(ob) ? ID_IS_LINKED_DATABLOCK(ob->data) : true));
- return (ob && ob->data && ID_IS_LINKED_DATABLOCK(ob->data));
+ BLI_assert(!ob || !ob->data || (ID_IS_LINKED(ob) ? ID_IS_LINKED(ob->data) : true));
+ return (ob && ob->data && ID_IS_LINKED(ob->data));
}
/* *************** PROXY **************** */
@@ -1275,7 +1275,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
/* only on local objects because this causes indirect links
* 'a -> b -> c', blend to point directly to a.blend
* when a.blend has a proxy thats linked into c.blend */
- if (!ID_IS_LINKED_DATABLOCK(ob))
+ if (!ID_IS_LINKED(ob))
id_lib_extern((ID *)dtar->id);
}
}
@@ -1293,7 +1293,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target)
void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
{
/* paranoia checks */
- if (ID_IS_LINKED_DATABLOCK(ob) || !ID_IS_LINKED_DATABLOCK(target)) {
+ if (ID_IS_LINKED(ob) || !ID_IS_LINKED(target)) {
printf("cannot make proxy\n");
return;
}
@@ -2670,7 +2670,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
printf("recalcob %s\n", ob->id.name + 2);
/* handle proxy copy for target */
- if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
+ if (ID_IS_LINKED(ob) && ob->proxy_from) {
// printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
if (ob->proxy_from->proxy_group) { /* transform proxy into group space */
Object *obg = ob->proxy_from->proxy_group;
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 457263f854b..ebd090bcc5b 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -203,7 +203,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx,
break;
}
case OB_ARMATURE:
- if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
+ if (ID_IS_LINKED(ob) && ob->proxy_from) {
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);
@@ -315,7 +315,7 @@ void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx),
// XXX: it's almost redundant now...
/* Handle proxy copy for target, */
- if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) {
+ if (ID_IS_LINKED(ob) && ob->proxy_from) {
if (ob->proxy_from->proxy_group) {
/* Transform proxy into group space. */
Object *obg = ob->proxy_from->proxy_group;
@@ -347,10 +347,3 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx,
ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME);
}
-
-void BKE_object_eval_proxy_backlink(EvaluationContext *UNUSED(eval_ctx), Object *ob)
-{
- if (ob->proxy) {
- ob->proxy->proxy_from = ob;
- }
-}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 489fc2f3710..08aca2a44a3 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -232,7 +232,7 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
int tot = 0;
for (ima = bmain->image.first; ima; ima = ima->id.next) {
- if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED_DATABLOCK(ima)) {
+ if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED(ima)) {
if (ima->source == IMA_SRC_FILE) {
BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
tot ++;
@@ -245,14 +245,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose)
}
for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
- if (vfont->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(vfont) && BKE_vfont_is_builtin(vfont) == false) {
+ if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) && BKE_vfont_is_builtin(vfont) == false) {
vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name);
tot ++;
}
}
for (sound = bmain->sound.first; sound; sound = sound->id.next) {
- if (sound->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(sound)) {
+ if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) {
sound->packedfile = newPackedFile(reports, sound->name, bmain->name);
tot++;
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 934c5b9ff06..42b818b35a5 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -3335,42 +3335,14 @@ ParticleSettings *BKE_particlesettings_copy(Main *bmain, ParticleSettings *part)
BLI_duplicatelist(&partn->dupliweights, &part->dupliweights);
- if (ID_IS_LINKED_DATABLOCK(part)) {
- BKE_id_expand_local(&partn->id);
- BKE_id_lib_local_paths(bmain, part->id.lib, &partn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &part->id, &partn->id);
return partn;
}
-void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part)
+void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(part)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, part, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &part->id);
- BKE_id_expand_local(&part->id);
- }
- else {
- ParticleSettings *part_new = BKE_particlesettings_copy(bmain, part);
-
- part_new->id.us = 0;
-
- BKE_libblock_remap(bmain, part, part_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &part->id, true, lib_local);
}
/************************************************/
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 858b6bd927b..3e37ee83cea 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -344,7 +344,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
}
}
- scen->preview = BKE_previewimg_copy(sce->preview);
+ BKE_previewimg_id_copy(&scen->id, &sce->id);
return scen;
}
@@ -355,6 +355,13 @@ void BKE_scene_groups_relink(Scene *sce)
BKE_rigidbody_world_groups_relink(sce->rigidbody_world);
}
+void BKE_scene_make_local(Main *bmain, Scene *sce, const bool lib_local)
+{
+ /* For now should work, may need more work though to support all possible corner cases
+ * (also scene_copy probably needs some love). */
+ BKE_id_make_local_generic(bmain, &sce->id, true, lib_local);
+}
+
/** Free (or release) any data used by this scene (does not free the scene itself). */
void BKE_scene_free(Scene *sce)
{
@@ -1123,7 +1130,7 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame)
Base *BKE_scene_base_add(Scene *sce, Object *ob)
{
- Base *b = MEM_callocN(sizeof(*b), "BKE_scene_base_add");
+ Base *b = MEM_callocN(sizeof(*b), __func__);
BLI_addhead(&sce->base, b);
b->object = ob;
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 3de4a426973..ce7c520438a 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -123,28 +123,34 @@ static ImBuf *prepare_effect_imbufs(const SeqRenderData *context, ImBuf *ibuf1,
out = IMB_allocImBuf(x, y, 32, IB_rect);
}
- if (ibuf1 && !ibuf1->rect_float && out->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true);
- }
- if (ibuf2 && !ibuf2->rect_float && out->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true);
- }
- if (ibuf3 && !ibuf3->rect_float && out->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true);
- }
+ if (out->rect_float) {
+ if (ibuf1 && !ibuf1->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true);
+ }
+
+ if (ibuf2 && !ibuf2->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true);
+ }
+
+ if (ibuf3 && !ibuf3->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true);
+ }
- if (ibuf1 && !ibuf1->rect && !out->rect_float) {
- IMB_rect_from_float(ibuf1);
- }
- if (ibuf2 && !ibuf2->rect && !out->rect_float) {
- IMB_rect_from_float(ibuf2);
- }
- if (ibuf3 && !ibuf3->rect && !out->rect_float) {
- IMB_rect_from_float(ibuf3);
+ IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name);
}
+ else {
+ if (ibuf1 && !ibuf1->rect) {
+ IMB_rect_from_float(ibuf1);
+ }
- if (out->rect_float)
- IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name);
+ if (ibuf2 && !ibuf2->rect) {
+ IMB_rect_from_float(ibuf2);
+ }
+
+ if (ibuf3 && !ibuf3->rect) {
+ IMB_rect_from_float(ibuf3);
+ }
+ }
/* If effect only affecting a single channel, forward input's metadata to the output. */
if (ibuf1 != NULL && ibuf1 == ibuf2 && ibuf2 == ibuf3) {
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 5ef502e0182..6067a8b2d9b 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -1308,41 +1308,40 @@ StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra)
static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfra, int chanshown)
{
- Sequence *seq;
- Sequence *effect_inputs[MAXSEQ + 1];
- int i, totseq = 0, num_effect_inputs = 0;
+ /* Use arbitrary sized linked list, the size could be over MAXSEQ. */
+ LinkNodePair effect_inputs = {NULL, NULL};
+ int totseq = 0;
memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1));
- seq = seqbase->first;
- while (seq) {
- if (seq->startdisp <= cfra && seq->enddisp > cfra) {
+ for (Sequence *seq = seqbase->first; seq; seq = seq->next) {
+ if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) {
if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) {
+
if (seq->seq1) {
- effect_inputs[num_effect_inputs++] = seq->seq1;
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq1);
}
if (seq->seq2) {
- effect_inputs[num_effect_inputs++] = seq->seq2;
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq2);
}
if (seq->seq3) {
- effect_inputs[num_effect_inputs++] = seq->seq3;
+ BLI_linklist_append_alloca(&effect_inputs, seq->seq3);
}
}
seq_arr[seq->machine] = seq;
totseq++;
}
- seq = seq->next;
}
/* Drop strips which are used for effect inputs, we don't want
* them to blend into render stack in any other way than effect
* string rendering.
*/
- for (i = 0; i < num_effect_inputs; i++) {
- seq = effect_inputs[i];
+ for (LinkNode *seq_item = effect_inputs.list; seq_item; seq_item = seq_item->next) {
+ Sequence *seq = seq_item->link;
/* It's possible that effetc strip would be placed to the same
* 'machine' as it's inputs. We don't want to clear such strips
* from the stack.
@@ -1826,8 +1825,10 @@ static void seq_proxy_build_frame(
IMB_freeImBuf(ibuf);
}
-/* returns whether the file this context would read from even exist, if not, don't create the context
-*/
+/**
+ * Returns whether the file this context would read from even exist,
+ * if not, don't create the context
+ */
static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const int view_id)
{
if ((scene->r.scemode & R_MULTIVIEW) == 0)
@@ -1862,8 +1863,9 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con
return false;
}
-/** This returns the maximum possible number of required contexts
-*/
+/**
+ * This returns the maximum possible number of required contexts
+ */
static int seq_proxy_context_count(Sequence *seq, Scene *scene)
{
int num_views = 1;
@@ -3556,7 +3558,7 @@ static ImBuf *seq_render_strip(
if (ibuf == NULL) {
/* MOVIECLIPs have their own proxy management */
- if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) {
+ if (seq->type != SEQ_TYPE_MOVIECLIP) {
ibuf = seq_proxy_fetch(context, seq, cfra);
is_proxy_image = (ibuf != NULL);
}
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 414be73e234..2f47966ec55 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -155,6 +155,11 @@ void BKE_sound_free(bSound *sound)
#endif /* WITH_AUDASPACE */
}
+void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &sound->id, true, lib_local);
+}
+
#ifdef WITH_AUDASPACE
static const char *force_device = NULL;
diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c
index a91d8657179..ee6886e3fb2 100644
--- a/source/blender/blenkernel/intern/speaker.c
+++ b/source/blender/blenkernel/intern/speaker.c
@@ -77,42 +77,14 @@ Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk)
if (spkn->sound)
id_us_plus(&spkn->sound->id);
- if (ID_IS_LINKED_DATABLOCK(spk)) {
- BKE_id_expand_local(&spkn->id);
- BKE_id_lib_local_paths(G.main, spk->id.lib, &spkn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &spk->id, &spkn->id);
return spkn;
}
-void BKE_speaker_make_local(Main *bmain, Speaker *spk)
+void BKE_speaker_make_local(Main *bmain, Speaker *spk, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(spk)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, spk, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &spk->id);
- BKE_id_expand_local(&spk->id);
- }
- else {
- Speaker *spk_new = BKE_speaker_copy(bmain, spk);
-
- spk_new->id.us = 0;
-
- BKE_libblock_remap(bmain, spk, spk_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &spk->id, true, lib_local);
}
void BKE_speaker_free(Speaker *spk)
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index b0d19320230..04bcd366c3f 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -794,14 +794,20 @@ static void ss_sync_osd_from_derivedmesh(CCGSubSurf *ss,
static void ss_sync_from_derivedmesh(CCGSubSurf *ss,
DerivedMesh *dm,
float (*vertexCos)[3],
- int use_flat_subdiv)
+ int use_flat_subdiv,
+ bool use_subdiv_uvs)
{
+#ifndef WITH_OPENSUBDIV
+ UNUSED_VARS(use_subdiv_uvs);
+#endif
+
#ifdef WITH_OPENSUBDIV
/* Reset all related descriptors if actual mesh topology changed or if
* other evaluation-related settings changed.
*/
if (!ccgSubSurf_needGrids(ss)) {
/* TODO(sergey): Use vertex coordinates and flat subdiv flag. */
+ ccgSubSurf__sync_subdivUvs(ss, use_subdiv_uvs);
ccgSubSurf_checkTopologyChanged(ss, dm);
ss_sync_osd_from_derivedmesh(ss, dm);
}
@@ -1801,7 +1807,7 @@ static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEd
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
/* TODO(sergey): We currently only support all edges drawing. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true)) {
+ if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
}
return;
@@ -2638,7 +2644,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
int mat_nr = -1;
bool draw_smooth = false;
int start_draw_patch = -1, num_draw_patches = 0;
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) {
return;
}
if (setMaterial == NULL) {
@@ -2750,7 +2756,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
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) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) {
return;
}
for (i = 0; i < num_base_faces; ++i) {
@@ -3193,7 +3199,7 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
int new_matnr;
bool draw_smooth;
GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
return;
}
/* TODO(sergey): Single matierial currently. */
@@ -3386,19 +3392,6 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
int mat_index;
int tot_element, start_element, tot_drawn;
-#ifdef WITH_OPENSUBDIV
- if (ccgdm->useGpuBackend) {
- if (ccgSubSurf_prepareGLMesh(ss, true) == false) {
- return;
- }
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
- return;
- }
-#endif
-
- CCG_key_top_level(&key, ss);
- ccgdm_pbvh_update(ccgdm);
-
if (use_colors) {
colType = CD_TEXTURE_MLOOPCOL;
mloopcol = dm->getLoopDataArray(dm, colType);
@@ -3412,6 +3405,87 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
}
}
+#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;
+ }
+ }
+ return;
+ }
+#endif
+
+ CCG_key_top_level(&key, ss);
+ ccgdm_pbvh_update(ccgdm);
+
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
GPU_triangle_setup(dm);
@@ -3472,7 +3546,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
if (!flush && compareDrawOptions) {
/* also compare draw options and flush buffer if they're different
- * need for face selection highlight in edit mode */
+ * need for face selection highlight in edit mode */
flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
}
@@ -3581,7 +3655,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
*/
glColor3f(0.8f, 0.8f, 0.8f);
}
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
return;
}
if (faceFlags) {
@@ -3780,7 +3854,7 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm,
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
/* TODO(sergey): Only draw edges from base mesh. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true)) {
+ if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) {
ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
}
@@ -4970,7 +5044,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
#ifdef WITH_OPENSUBDIV
ccgSubSurf_setSkipGrids(smd->emCache, use_gpu_backend);
#endif
- ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple);
+ ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple, useSubsurfUv);
result = getCCGDerivedMesh(smd->emCache,
drawInteriorEdges,
useSubsurfUv, dm, use_gpu_backend);
@@ -4985,7 +5059,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
ss = _getSubSurf(NULL, levels, 3, useSimple | CCG_USE_ARENA | CCG_CALC_NORMALS);
- ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
result = getCCGDerivedMesh(ss,
drawInteriorEdges, useSubsurfUv, dm, false);
@@ -5016,7 +5090,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
if (useIncremental && (flags & SUBSURF_IS_FINAL_CALC)) {
smd->mCache = ss = _getSubSurf(smd->mCache, levels, 3, useSimple | useAging | CCG_CALC_NORMALS);
- ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
result = getCCGDerivedMesh(smd->mCache,
drawInteriorEdges,
@@ -5056,7 +5130,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
#ifdef WITH_OPENSUBDIV
ccgSubSurf_setSkipGrids(ss, use_gpu_backend);
#endif
- ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple, useSubsurfUv);
result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm, use_gpu_backend);
@@ -5085,7 +5159,7 @@ void subsurf_calculate_limit_positions(Mesh *me, float (*r_positions)[3])
CCGVertIterator vi;
DerivedMesh *dm = CDDM_from_mesh(me);
- ss_sync_from_derivedmesh(ss, dm, NULL, 0);
+ ss_sync_from_derivedmesh(ss, dm, NULL, 0, 0);
for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
CCGVert *v = ccgVertIterator_getCurrent(&vi);
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 269d6d32b31..1636042f479 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -491,14 +491,16 @@ Text *BKE_text_copy(Main *bmain, Text *ta)
init_undo_text(tan);
- if (ID_IS_LINKED_DATABLOCK(ta)) {
- BKE_id_expand_local(&tan->id);
- BKE_id_lib_local_paths(bmain, ta->id.lib, &tan->id);
- }
+ BKE_id_copy_ensure_local(bmain, &ta->id, &tan->id);
return tan;
}
+void BKE_text_make_local(Main *bmain, Text *text, const bool lib_local)
+{
+ BKE_id_make_local_generic(bmain, &text->id, true, lib_local);
+}
+
void BKE_text_clear(Text *text) /* called directly from rna */
{
int oldstate;
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index e34d632f2ca..2d3ecad19ad 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -863,7 +863,6 @@ Tex *BKE_texture_copy(Main *bmain, Tex *tex)
if (texn->pd) texn->pd = BKE_texture_pointdensity_copy(texn->pd);
if (texn->vd) texn->vd = MEM_dupallocN(texn->vd);
if (texn->ot) texn->ot = BKE_texture_ocean_copy(texn->ot);
- if (tex->preview) texn->preview = BKE_previewimg_copy(tex->preview);
if (tex->nodetree) {
if (tex->nodetree->execdata) {
@@ -871,13 +870,10 @@ Tex *BKE_texture_copy(Main *bmain, Tex *tex)
}
texn->nodetree = ntreeCopyTree(bmain, tex->nodetree);
}
-
- texn->preview = BKE_previewimg_copy(tex->preview);
- if (ID_IS_LINKED_DATABLOCK(tex)) {
- BKE_id_expand_local(&texn->id);
- BKE_id_lib_local_paths(bmain, tex->id.lib, &texn->id);
- }
+ BKE_previewimg_id_copy(&texn->id, &tex->id);
+
+ BKE_id_copy_ensure_local(bmain, &tex->id, &texn->id);
return texn;
}
@@ -918,34 +914,9 @@ Tex *BKE_texture_localize(Tex *tex)
/* ------------------------------------------------------------------------- */
-void BKE_texture_make_local(Main *bmain, Tex *tex)
+void BKE_texture_make_local(Main *bmain, Tex *tex, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(tex)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, tex, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &tex->id);
- BKE_id_expand_local(&tex->id);
- }
- else {
- Tex *tex_new = BKE_texture_copy(bmain, tex);
-
- tex_new->id.us = 0;
-
- BKE_libblock_remap(bmain, tex, tex_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &tex->id, true, lib_local);
}
Tex *give_current_object_texture(Object *ob)
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 9df30a8acc9..3b56ea271d0 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -376,6 +376,9 @@ bool BKE_autotrack_context_step(AutoTrackContext *context)
#pragma omp parallel for if (context->num_tracks > 1)
for (track = 0; track < context->num_tracks; ++track) {
AutoTrackOptions *options = &context->options[track];
+ if (options->is_failed) {
+ continue;
+ }
libmv_Marker libmv_current_marker,
libmv_reference_marker,
libmv_tracked_marker;
@@ -463,16 +466,25 @@ void BKE_autotrack_context_sync(AutoTrackContext *context)
AutoTrackOptions *options = &context->options[track];
int track_frame = BKE_movieclip_remap_scene_to_clip_frame(
context->clips[options->clip_index], frame);
- if (options->is_failed && options->failed_frame == track_frame) {
- MovieTrackingMarker *prev_marker =
- BKE_tracking_marker_get_exact(options->track, frame);
- if (prev_marker) {
- marker = *prev_marker;
- marker.framenr = context->backwards ?
- track_frame - 1 :
- track_frame + 1;
- marker.flag |= MARKER_DISABLED;
- BKE_tracking_marker_insert(options->track, &marker);
+ if (options->is_failed) {
+ if (options->failed_frame == track_frame) {
+ MovieTrackingMarker *prev_marker =
+ BKE_tracking_marker_get_exact(
+ options->track,
+ context->backwards
+ ? frame + 1
+ : frame - 1);
+ if (prev_marker) {
+ marker = *prev_marker;
+ marker.framenr = track_frame;
+ marker.flag |= MARKER_DISABLED;
+ BKE_tracking_marker_insert(options->track, &marker);
+ continue;
+ }
+ }
+ if ((context->backwards && options->failed_frame > track_frame) ||
+ (!context->backwards && options->failed_frame < track_frame))
+ {
continue;
}
}
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index a40e4f72636..a90b1dee927 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -762,8 +762,8 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
final_ibuf = IMB_dupImBuf(orig_ibuf);
}
IMB_scaleImBuf(final_ibuf,
- ibuf->x / (1 << downscale),
- ibuf->y / (1 << downscale));
+ orig_ibuf->x / (1 << downscale),
+ orig_ibuf->y / (1 << downscale));
}
if (transform != NULL) {
@@ -780,7 +780,7 @@ static ImBuf *accessor_get_ibuf(TrackingImageAccessor *accessor,
}
if (input_mode == LIBMV_IMAGE_MODE_RGBA) {
- BLI_assert(ibuf->channels == 3 || ibuf->channels == 4);
+ BLI_assert(orig_ibuf->channels == 3 || orig_ibuf->channels == 4);
/* pass */
}
else /* if (input_mode == LIBMV_IMAGE_MODE_MONO) */ {
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 9795a8174f8..de1e3187a70 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -138,14 +138,11 @@ World *BKE_world_copy(Main *bmain, World *wrld)
wrldn->nodetree = ntreeCopyTree(bmain, wrld->nodetree);
}
- wrldn->preview = BKE_previewimg_copy(wrld->preview);
+ BKE_previewimg_id_copy(&wrldn->id, &wrld->id);
BLI_listbase_clear(&wrldn->gpumaterial);
- if (ID_IS_LINKED_DATABLOCK(wrld)) {
- BKE_id_expand_local(&wrldn->id);
- BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrldn->id);
- }
+ BKE_id_copy_ensure_local(bmain, &wrld->id, &wrldn->id);
return wrldn;
}
@@ -176,32 +173,7 @@ World *localize_world(World *wrld)
return wrldn;
}
-void BKE_world_make_local(Main *bmain, World *wrld)
+void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local)
{
- bool is_local = false, is_lib = false;
-
- /* - only lib users: do nothing
- * - only local users: set flag
- * - mixed: make copy
- */
-
- if (!ID_IS_LINKED_DATABLOCK(wrld)) {
- return;
- }
-
- BKE_library_ID_test_usages(bmain, wrld, &is_local, &is_lib);
-
- if (is_local) {
- if (!is_lib) {
- id_clear_lib_data(bmain, &wrld->id);
- BKE_id_expand_local(&wrld->id);
- }
- else {
- World *wrld_new = BKE_world_copy(bmain, wrld);
-
- wrld_new->id.us = 0;
-
- BKE_libblock_remap(bmain, wrld, wrld_new, ID_REMAP_SKIP_INDIRECT_USAGE);
- }
- }
+ BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local);
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index edeccf472c8..9dbc045f1b0 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -1672,9 +1672,6 @@ bool BKE_ffmpeg_alpha_channel_is_supported(RenderData *rd)
if (codec == AV_CODEC_ID_PNG)
return true;
- if (codec == AV_CODEC_ID_PNG)
- return true;
-
if (codec == AV_CODEC_ID_HUFFYUV)
return true;
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index b4a465bbc74..0b1b4d8ee8c 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -42,7 +42,7 @@ extern "C" {
#endif
/* for tables, button in UI, etc */
-#define BLENDER_MAX_THREADS 64
+#define BLENDER_MAX_THREADS 1024
struct ListBase;
struct TaskScheduler;
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
index 4bd404e5d73..0a8dafc2dc1 100644
--- a/source/blender/blenlib/intern/BLI_heap.c
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -32,7 +32,6 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_memarena.h"
#include "BLI_heap.h"
#include "BLI_strict_flags.h"
@@ -44,15 +43,37 @@ struct HeapNode {
unsigned int index;
};
+struct HeapNode_Chunk {
+ struct HeapNode_Chunk *prev;
+ unsigned int size;
+ unsigned int bufsize;
+ struct HeapNode buf[0];
+};
+
+/**
+ * Number of nodes to include per #HeapNode_Chunk when no reserved size is passed,
+ * or we allocate past the reserved number.
+ *
+ * \note Optimize number for 64kb allocs.
+ */
+#define HEAP_CHUNK_DEFAULT_NUM \
+ ((MEM_SIZE_OPTIMAL((1 << 16) - sizeof(struct HeapNode_Chunk))) / sizeof(HeapNode))
+
struct Heap {
unsigned int size;
unsigned int bufsize;
- MemArena *arena;
- HeapNode *freenodes;
HeapNode **tree;
+
+ struct {
+ /* Always keep at least one chunk (never NULL) */
+ struct HeapNode_Chunk *chunk;
+ /* when NULL, allocate a new chunk */
+ HeapNode *free;
+ } nodes;
};
-/* internal functions */
+/** \name Internal Functions
+ * \{ */
#define HEAP_PARENT(i) (((i) - 1) >> 1)
#define HEAP_LEFT(i) (((i) << 1) + 1)
@@ -92,11 +113,13 @@ static void heap_down(Heap *heap, unsigned int i)
smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i;
- if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest]))
+ if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) {
smallest = r;
+ }
- if (smallest == i)
+ if (smallest == i) {
break;
+ }
heap_swap(heap, i, smallest);
i = smallest;
@@ -108,25 +131,73 @@ static void heap_up(Heap *heap, unsigned int i)
while (i > 0) {
const unsigned int p = HEAP_PARENT(i);
- if (HEAP_COMPARE(heap->tree[p], heap->tree[i]))
+ if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) {
break;
-
+ }
heap_swap(heap, p, i);
i = p;
}
}
+/** \} */
-/***/
+
+/** \name Internal Memory Management
+ * \{ */
+
+static struct HeapNode_Chunk *heap_node_alloc_chunk(
+ unsigned int tot_nodes, struct HeapNode_Chunk *chunk_prev)
+{
+ struct HeapNode_Chunk *chunk = MEM_mallocN(
+ sizeof(struct HeapNode_Chunk) + (sizeof(HeapNode) * tot_nodes), __func__);
+ chunk->prev = chunk_prev;
+ chunk->bufsize = tot_nodes;
+ chunk->size = 0;
+ return chunk;
+}
+
+static struct HeapNode *heap_node_alloc(Heap *heap)
+{
+ HeapNode *node;
+
+ if (heap->nodes.free) {
+ node = heap->nodes.free;
+ heap->nodes.free = heap->nodes.free->ptr;
+ }
+ else {
+ struct HeapNode_Chunk *chunk = heap->nodes.chunk;
+ if (UNLIKELY(chunk->size == chunk->bufsize)) {
+ chunk = heap->nodes.chunk = heap_node_alloc_chunk(HEAP_CHUNK_DEFAULT_NUM, chunk);
+ }
+ node = &chunk->buf[chunk->size++];
+ }
+
+ return node;
+}
+
+static void heap_node_free(Heap *heap, HeapNode *node)
+{
+ node->ptr = heap->nodes.free;
+ heap->nodes.free = node;
+}
+
+/** \} */
+
+
+/** \name Public Heap API
+ * \{ */
/* use when the size of the heap is known in advance */
Heap *BLI_heap_new_ex(unsigned int tot_reserve)
{
- Heap *heap = (Heap *)MEM_callocN(sizeof(Heap), __func__);
+ Heap *heap = MEM_mallocN(sizeof(Heap), __func__);
/* ensure we have at least one so we can keep doubling it */
+ heap->size = 0;
heap->bufsize = MAX2(1u, tot_reserve);
- heap->tree = (HeapNode **)MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree");
- heap->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "heap arena");
+ heap->tree = MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree");
+
+ heap->nodes.chunk = heap_node_alloc_chunk((tot_reserve > 1) ? tot_reserve : HEAP_CHUNK_DEFAULT_NUM, NULL);
+ heap->nodes.free = NULL;
return heap;
}
@@ -146,8 +217,15 @@ void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp)
}
}
+ struct HeapNode_Chunk *chunk = heap->nodes.chunk;
+ do {
+ struct HeapNode_Chunk *chunk_prev;
+ chunk_prev = chunk->prev;
+ MEM_freeN(chunk);
+ chunk = chunk_prev;
+ } while (chunk);
+
MEM_freeN(heap->tree);
- BLI_memarena_free(heap->arena);
MEM_freeN(heap);
}
@@ -160,10 +238,16 @@ void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
ptrfreefp(heap->tree[i]->ptr);
}
}
-
heap->size = 0;
- BLI_memarena_clear(heap->arena);
- heap->freenodes = NULL;
+
+ /* Remove all except the last chunk */
+ while (heap->nodes.chunk->prev) {
+ struct HeapNode_Chunk *chunk_prev = heap->nodes.chunk->prev;
+ MEM_freeN(heap->nodes.chunk);
+ heap->nodes.chunk = chunk_prev;
+ }
+ heap->nodes.chunk->size = 0;
+ heap->nodes.free = NULL;
}
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
@@ -175,13 +259,7 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
heap->tree = MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree));
}
- if (heap->freenodes) {
- node = heap->freenodes;
- heap->freenodes = heap->freenodes->ptr;
- }
- else {
- node = (HeapNode *)BLI_memarena_alloc(heap->arena, sizeof(*node));
- }
+ node = heap_node_alloc(heap);
node->ptr = ptr;
node->value = value;
@@ -217,8 +295,7 @@ void *BLI_heap_popmin(Heap *heap)
BLI_assert(heap->size != 0);
- heap->tree[0]->ptr = heap->freenodes;
- heap->freenodes = heap->tree[0];
+ heap_node_free(heap, heap->tree[0]);
if (--heap->size) {
heap_swap(heap, 0, heap->size);
@@ -254,3 +331,4 @@ void *BLI_heap_node_ptr(HeapNode *node)
return node->ptr;
}
+/** \} */
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 92f4e998206..b14007a88cb 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -1917,7 +1917,7 @@ static void dist_squared_ray_to_aabb_scaled_v3_precalc(
}
/* un-normalize ray */
if (ray_is_normalized && scale &&
- (data->scale[0] != 1.0f || data->scale[1] != 1.0f || data->scale[2] != 1.0f))
+ (data->scale[0] != 1.0f || data->scale[1] != 1.0f || data->scale[2] != 1.0f))
{
data->ray.direction[0] = ray_direction[0] * data->scale[0];
data->ray.direction[1] = ray_direction[1] * data->scale[1];
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 2f7b1386a27..7fd08569984 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -115,7 +115,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_brush.h"
#include "BKE_cloth.h"
#include "BKE_constraint.h"
@@ -1283,7 +1283,7 @@ void blo_freefiledata(FileData *fd)
if (fd->filesdna)
DNA_sdna_free(fd->filesdna);
if (fd->compflags)
- MEM_freeN(fd->compflags);
+ MEM_freeN((void *)fd->compflags);
if (fd->datamap)
oldnewmap_free(fd->datamap);
@@ -2147,6 +2147,7 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p
}
prv->gputexture[i] = NULL;
}
+ prv->icon_id = 0;
}
return prv;
@@ -2718,7 +2719,7 @@ static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock
IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
-/* singe node tree (also used for material/scene trees), ntree is not NULL */
+/* Single node tree (also used for material/scene trees), ntree is not NULL */
static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
{
bNode *node;
@@ -2761,22 +2762,6 @@ static void lib_link_nodetree(FileData *fd, Main *main)
}
}
-/* get node tree stored locally in other IDs */
-static bNodeTree *nodetree_from_id(ID *id)
-{
- if (!id)
- return NULL;
- switch (GS(id->name)) {
- case ID_SCE: return ((Scene *)id)->nodetree;
- case ID_MA: return ((Material *)id)->nodetree;
- case ID_WO: return ((World *)id)->nodetree;
- case ID_LA: return ((Lamp *)id)->nodetree;
- case ID_TE: return ((Tex *)id)->nodetree;
- case ID_LS: return ((FreestyleLineStyle *)id)->nodetree;
- }
- return NULL;
-}
-
/* updates group node socket identifier so that
* external links to/from the group node are preserved.
*/
@@ -6355,11 +6340,9 @@ static void lib_link_screen(FileData *fd, Main *main)
snode->id = newlibadr(fd, sc->id.lib, snode->id);
snode->from = newlibadr(fd, sc->id.lib, snode->from);
- ntree = nodetree_from_id(snode->id);
- if (ntree)
- snode->nodetree = ntree;
- else {
- snode->nodetree = newlibadr_us(fd, sc->id.lib, snode->nodetree);
+ if (snode->id) {
+ ntree = ntreeFromID(snode->id);
+ snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree);
}
for (path = snode->treepath.first; path; path = path->next) {
@@ -6739,11 +6722,11 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL);
snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE);
- ntree = nodetree_from_id(snode->id);
- if (ntree)
- snode->nodetree = ntree;
- else
- snode->nodetree = restore_pointer_by_name(id_map, (ID*)snode->nodetree, USER_REAL);
+ if (snode->id) {
+ ntree = ntreeFromID(snode->id);
+ snode->nodetree = ntree ? ntree :
+ restore_pointer_by_name(id_map, (ID *)snode->nodetree, USER_REAL);
+ }
for (path = snode->treepath.first; path; path = path->next) {
if (path == snode->treepath.first) {
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index b054cd0031d..7719aaa2b0d 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -75,7 +75,7 @@ typedef struct FileData {
// general reading variables
struct SDNA *filesdna;
const struct SDNA *memsdna;
- char *compflags; /* array of eSDNA_StructCompare */
+ const char *compflags; /* array of eSDNA_StructCompare */
int fileversion;
int id_name_offs; /* used to retrieve ID names from (bhead+1) */
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index b7b6ace3c1a..a254a854c66 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1194,8 +1194,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
if (camera->stereo.pole_merge_angle_from == 0.0f &&
camera->stereo.pole_merge_angle_to == 0.0f)
{
- camera->stereo.pole_merge_angle_from = DEG2RAD(60.0f);
- camera->stereo.pole_merge_angle_to = DEG2RAD(75.0f);
+ camera->stereo.pole_merge_angle_from = DEG2RADF(60.0f);
+ camera->stereo.pole_merge_angle_to = DEG2RADF(75.0f);
}
}
@@ -1212,5 +1212,24 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
+
+ if (!DNA_struct_elem_find(fd->filesdna, "BooleanModifierData", "float", "double_threshold")) {
+ Object *ob;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Boolean) {
+ BooleanModifierData *bmd = (BooleanModifierData *)md;
+ bmd->double_threshold = 1e-6f;
+ }
+ }
+ }
+ }
+
+ for (Brush *br = main->brush.first; br; br = br->id.next) {
+ if (br->sculpt_tool == SCULPT_TOOL_FLATTEN) {
+ br->flag |= BRUSH_ACCUMULATE;
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index ad7a3c5b9c4..0ed7a397e0b 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -256,6 +256,11 @@ void BLO_update_defaults_startup_blend(Main *bmain)
if (br) {
br->alpha = 1.0f;
}
+
+ br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Flatten/Contrast");
+ if (br) {
+ br->flag |= BRUSH_ACCUMULATE;
+ }
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index d949dcf48c7..903cae48858 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -2275,7 +2275,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase)
mesh->edit_btmesh = NULL;
/* now fill in polys to mfaces */
- /* XXX This breaks writing desing, by using temp allocated memory, which will likely generate
+ /* XXX This breaks writing design, by using temp allocated memory, which will likely generate
* duplicates in stored 'old' addresses.
* This is very bad, but do not see easy way to avoid this, aside from generating those data
* outside of save process itself.
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 13b6a3c13c5..c500d7b9ec2 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -48,31 +48,6 @@
#include "intern/bmesh_private.h"
/**
- * \brief TEST EDGE SIDE and POINT IN TRIANGLE
- *
- * Point in triangle tests stolen from scanfill.c.
- * Used for tessellator
- */
-
-static bool testedgesidef(const float v1[2], const float v2[2], const float v3[2])
-{
- /* is v3 to the right of v1 - v2 ? With exception: v3 == v1 || v3 == v2 */
- double inp;
-
- //inp = (v2[cox] - v1[cox]) * (v1[coy] - v3[coy]) + (v1[coy] - v2[coy]) * (v1[cox] - v3[cox]);
- inp = (v2[0] - v1[0]) * (v1[1] - v3[1]) + (v1[1] - v2[1]) * (v1[0] - v3[0]);
-
- if (inp < 0.0) {
- return false;
- }
- else if (inp == 0) {
- if (v1[0] == v3[0] && v1[1] == v3[1]) return false;
- if (v2[0] == v3[0] && v2[1] == v3[1]) return false;
- }
- return true;
-}
-
-/**
* \brief COMPUTE POLY NORMAL (BMFace)
*
* Same as #normal_poly_v3 but operates directly on a bmesh face.
@@ -603,29 +578,6 @@ void BM_face_calc_center_mean_weighted(const BMFace *f, float r_cent[3])
}
/**
- * \brief BM LEGAL EDGES
- *
- * takes in a face and a list of edges, and sets to NULL any edge in
- * the list that bridges a concave region of the face or intersects
- * any of the faces's edges.
- */
-static void scale_edge_v2f(float v1[2], float v2[2], const float fac)
-{
- float mid[2];
-
- mid_v2_v2v2(mid, v1, v2);
-
- sub_v2_v2v2(v1, v1, mid);
- sub_v2_v2v2(v2, v2, mid);
-
- mul_v2_fl(v1, fac);
- mul_v2_fl(v2, fac);
-
- add_v2_v2v2(v1, v1, mid);
- add_v2_v2v2(v2, v2, mid);
-}
-
-/**
* \brief POLY ROTATE PLANE
*
* Rotates a polygon so that it's
@@ -910,67 +862,6 @@ void BM_face_normal_flip(BMesh *bm, BMFace *f)
BM_face_normal_flip_ex(bm, f, cd_loop_mdisp_offset, true);
}
-/* detects if two line segments cross each other (intersects).
- * note, there could be more winding cases then there needs to be. */
-static bool line_crosses_v2f(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
-{
-
-#define GETMIN2_AXIS(a, b, ma, mb, axis) \
- { \
- ma[axis] = min_ff(a[axis], b[axis]); \
- mb[axis] = max_ff(a[axis], b[axis]); \
- } (void)0
-
-#define GETMIN2(a, b, ma, mb) \
- { \
- GETMIN2_AXIS(a, b, ma, mb, 0); \
- GETMIN2_AXIS(a, b, ma, mb, 1); \
- } (void)0
-
-#define EPS (FLT_EPSILON * 15)
-
- int w1, w2, w3, w4, w5 /*, re */;
- float mv1[2], mv2[2], mv3[2], mv4[2];
-
- /* now test winding */
- w1 = testedgesidef(v1, v3, v2);
- w2 = testedgesidef(v2, v4, v1);
- w3 = !testedgesidef(v1, v2, v3);
- w4 = testedgesidef(v3, v2, v4);
- w5 = !testedgesidef(v3, v1, v4);
-
- if (w1 == w2 && w2 == w3 && w3 == w4 && w4 == w5) {
- return true;
- }
-
- GETMIN2(v1, v2, mv1, mv2);
- GETMIN2(v3, v4, mv3, mv4);
-
- /* do an interval test on the x and y axes */
- /* first do x axis */
- if (fabsf(v1[1] - v2[1]) < EPS &&
- fabsf(v3[1] - v4[1]) < EPS &&
- fabsf(v1[1] - v3[1]) < EPS)
- {
- return (mv4[0] >= mv1[0] && mv3[0] <= mv2[0]);
- }
-
- /* now do y axis */
- if (fabsf(v1[0] - v2[0]) < EPS &&
- fabsf(v3[0] - v4[0]) < EPS &&
- fabsf(v1[0] - v3[0]) < EPS)
- {
- return (mv4[1] >= mv1[1] && mv3[1] <= mv2[1]);
- }
-
- return false;
-
-#undef GETMIN2_AXIS
-#undef GETMIN2
-#undef EPS
-
-}
-
/**
* BM POINT IN FACE
*
@@ -1268,121 +1159,103 @@ void BM_face_triangulate(
*/
void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
{
- const int len2 = len * 2;
- BMLoop *l;
- float v1[2], v2[2], v3[2], mid[2], *p1, *p2, *p3, *p4;
float out[2] = {-FLT_MAX, -FLT_MAX};
+ float center[2] = {0.0f, 0.0f};
float axis_mat[3][3];
float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
- float (*edgeverts)[2] = BLI_array_alloca(edgeverts, len2);
- float fac1 = 1.0000001f, fac2 = 0.9f; //9999f; //0.999f;
- int i, j, a = 0, clen;
+ const float *(*edgeverts)[2] = BLI_array_alloca(edgeverts, len);
+ BMLoop *l;
+ int i, i_prev, j;
BLI_assert(BM_face_is_normal_valid(f));
axis_dominant_v3_to_m3(axis_mat, f->no);
for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
- BM_elem_index_set(l, i); /* set_dirty */
mul_v2_m3v3(projverts[i], axis_mat, l->v->co);
+ add_v2_v2(center, projverts[i]);
}
- bm->elem_index_dirty |= BM_LOOP;
/* first test for completely convex face */
if (is_poly_convex_v2((const float (*)[2])projverts, f->len)) {
return;
}
+ mul_v2_fl(center, 1.0f / f->len);
+
for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
+ BM_elem_index_set(l, i); /* set_dirty */
+
+ /* center the projection for maximum accuracy */
+ sub_v2_v2(projverts[i], center);
+
out[0] = max_ff(out[0], projverts[i][0]);
out[1] = max_ff(out[1], projverts[i][1]);
}
+ bm->elem_index_dirty |= BM_LOOP;
/* ensure we are well outside the face bounds (value is arbitrary) */
add_v2_fl(out, 1.0f);
for (i = 0; i < len; i++) {
- copy_v2_v2(edgeverts[a + 0], projverts[BM_elem_index_get(loops[i][0])]);
- copy_v2_v2(edgeverts[a + 1], projverts[BM_elem_index_get(loops[i][1])]);
- scale_edge_v2f(edgeverts[a + 0], edgeverts[a + 1], fac2);
- a += 2;
+ edgeverts[i][0] = projverts[BM_elem_index_get(loops[i][0])];
+ edgeverts[i][1] = projverts[BM_elem_index_get(loops[i][1])];
}
/* do convexity test */
for (i = 0; i < len; i++) {
- copy_v2_v2(v2, edgeverts[i * 2 + 0]);
- copy_v2_v2(v3, edgeverts[i * 2 + 1]);
-
- mid_v2_v2v2(mid, v2, v3);
+ float mid[2];
+ mid_v2_v2v2(mid, edgeverts[i][0], edgeverts[i][1]);
- clen = 0;
- for (j = 0; j < f->len; j++) {
- p1 = projverts[j];
- p2 = projverts[(j + 1) % f->len];
-
-#if 0
- copy_v2_v2(v1, p1);
- copy_v2_v2(v2, p2);
-
- scale_edge_v2f(v1, v2, fac1);
- if (line_crosses_v2f(v1, v2, mid, out)) {
- clen++;
+ int isect = 0;
+ int j_prev;
+ for (j = 0, j_prev = f->len - 1; j < f->len; j_prev = j++) {
+ const float *f_edge[2] = {projverts[j_prev], projverts[j]};
+ if (isect_seg_seg_v2(UNPACK2(f_edge), mid, out) == ISECT_LINE_LINE_CROSS) {
+ isect++;
}
-#else
- if (line_crosses_v2f(p1, p2, mid, out)) {
- clen++;
- }
-#endif
}
- if (clen % 2 == 0) {
+ if (isect % 2 == 0) {
loops[i][0] = NULL;
}
}
- /* do line crossing tests */
- for (i = 0; i < f->len; i++) {
- p1 = projverts[i];
- p2 = projverts[(i + 1) % f->len];
-
- copy_v2_v2(v1, p1);
- copy_v2_v2(v2, p2);
-
- scale_edge_v2f(v1, v2, fac1);
+#define EDGE_SHARE_VERT(e1, e2) \
+ ((ELEM((e1)[0], (e2)[0], (e2)[1])) || \
+ (ELEM((e1)[1], (e2)[0], (e2)[1])))
+ /* do line crossing tests */
+ for (i = 0, i_prev = f->len - 1; i < f->len; i_prev = i++) {
+ const float *f_edge[2] = {projverts[i_prev], projverts[i]};
for (j = 0; j < len; j++) {
- if (!loops[j][0]) {
- continue;
- }
-
- p3 = edgeverts[j * 2];
- p4 = edgeverts[j * 2 + 1];
-
- if (line_crosses_v2f(v1, v2, p3, p4)) {
- loops[j][0] = NULL;
+ if ((loops[j][0] != NULL) &&
+ !EDGE_SHARE_VERT(f_edge, edgeverts[j]))
+ {
+ if (isect_seg_seg_v2(UNPACK2(f_edge), UNPACK2(edgeverts[j])) == ISECT_LINE_LINE_CROSS) {
+ loops[j][0] = NULL;
+ }
}
}
}
+ /* self intersect tests */
for (i = 0; i < len; i++) {
- for (j = 0; j < len; j++) {
- if (j != i && loops[i][0] && loops[j][0]) {
- p1 = edgeverts[i * 2];
- p2 = edgeverts[i * 2 + 1];
- p3 = edgeverts[j * 2];
- p4 = edgeverts[j * 2 + 1];
-
- copy_v2_v2(v1, p1);
- copy_v2_v2(v2, p2);
-
- scale_edge_v2f(v1, v2, fac1);
-
- if (line_crosses_v2f(v1, v2, p3, p4)) {
- loops[i][0] = NULL;
+ if (loops[i][0]) {
+ for (j = i + 1; j < len; j++) {
+ if ((loops[j][0] != NULL) &&
+ !EDGE_SHARE_VERT(edgeverts[i], edgeverts[j]))
+ {
+ if (isect_seg_seg_v2(UNPACK2(edgeverts[i]), UNPACK2(edgeverts[j])) == ISECT_LINE_LINE_CROSS) {
+ loops[i][0] = NULL;
+ break;
+ }
}
}
}
}
+
+#undef EDGE_SHARE_VERT
}
/**
diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
index 9b3e1d38feb..b8acc9d09b8 100644
--- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c
+++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
@@ -63,7 +63,7 @@ static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const f
return delta_z;
}
-static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle)
+static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle_cos)
{
BMLoop *l_iter, *l_first;
BMLoop **l_arr = BLI_array_alloca(l_arr, f->len);
@@ -73,7 +73,7 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r
/* angle finding */
float err_best = FLT_MAX;
- float angle_best = FLT_MAX;
+ float angle_best_cos = -FLT_MAX;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
i_a = 0;
@@ -108,7 +108,7 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r
l_pair[0] = l_a;
l_pair[1] = l_b;
- angle_best = angle_normalized_v3v3(no_a, no_b);
+ angle_best_cos = dot_v3v3(no_a, no_b);
found = true;
}
}
@@ -117,17 +117,17 @@ static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r
}
}
- *r_angle = angle_best;
+ *r_angle_cos = angle_best_cos;
return found;
}
-static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit)
+static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit_cos)
{
BMLoop *l_pair[2];
- float angle;
+ float angle_cos;
- if (bm_face_split_find(bm, f, l_pair, &angle) && (angle > angle_limit)) {
+ if (bm_face_split_find(bm, f, l_pair, &angle_cos) && (angle_cos < angle_limit_cos)) {
BMFace *f_new;
BMLoop *l_new;
@@ -154,7 +154,7 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op)
bool changed = false;
BLI_LINKSTACK_DECLARE(fstack, BMFace *);
- const float angle_limit = BMO_slot_float_get(op->slots_in, "angle_limit");
+ const float angle_limit_cos = cosf(BMO_slot_float_get(op->slots_in, "angle_limit"));
BLI_LINKSTACK_INIT(fstack);
@@ -166,7 +166,7 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op)
while ((f = BLI_LINKSTACK_POP(fstack))) {
BMFace *f_pair[2];
- if (bm_face_split_by_angle(bm, f, f_pair, angle_limit)) {
+ if (bm_face_split_by_angle(bm, f, f_pair, angle_limit_cos)) {
int j;
for (j = 0; j < 2; j++) {
BM_face_normal_update(f_pair[j]);
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index 3eb6fe0cb97..05322a570a7 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -124,8 +124,8 @@ typedef struct PathLinkState {
} PathLinkState;
/**
- \name Min Dist Dir Util
-
+ * \name Min Dist Dir Util
+ *
* Simply getting the closest intersecting vert/edge is _not_ good enough. see T43792
* we need to get the closest in both directions since the absolute closest may be a dead-end.
*
diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c
index f0738303d5c..73dbee25be3 100644
--- a/source/blender/bmesh/operators/bmo_normals.c
+++ b/source/blender/bmesh/operators/bmo_normals.c
@@ -86,7 +86,7 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f
int f_start_index;
int i;
- /* Search for the best loop. Members are comapred in-order defined here. */
+ /* Search for the best loop. Members are compared in-order defined here. */
struct {
/* Squared distance from the center to the loops vertex 'l->v'.
* The normalized direction between the center and this vertex is also used for the dot-products below. */
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index b4a77bf1a38..ce031e1c230 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -1099,7 +1099,8 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op)
BMFace *f;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
- if (!BMO_face_flag_test(bm, f, FACE_OUT)) {
+ /* could support ngons, other areas would need updating too, see T48926. */
+ if ((f->len <= 4) && !BMO_face_flag_test(bm, f, FACE_OUT)) {
BMIter liter;
BMLoop *l;
bool ok = false;
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 4dc1c8a9f00..b647f5a667d 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -1648,9 +1648,11 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr
}
}
-/* Special case of build_boundary when a single edge is beveled.
- * The 'width adjust' part of build_boundary has been done already, and
- * efirst is the first beveled edge at vertex bv. */
+/**
+ * Special case of build_boundary when a single edge is beveled.
+ * The 'width adjust' part of build_boundary has been done already,
+ * and \a efirst is the first beveled edge at vertex \a bv.
+*/
static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct)
{
MemArena *mem_arena = bp->mem_arena;
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index f06f299d381..226f319cefd 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -904,6 +904,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
i++;
}
}
+
// EMISSION
// color
if (ef->getEmission().isColor()) {
@@ -919,8 +920,22 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
i++;
}
}
-
- if (ef->getOpacity().isTexture()) {
+
+ // TRANSPARENT
+ // color
+ if (ef->getOpacity().isColor()) {
+ col = ef->getTransparent().getColor();
+ float alpha = ef->getTransparency().getFloatValue();
+ if (col.isValid()) {
+ alpha *= col.getAlpha(); // Assuming A_ONE opaque mode
+ }
+ if (col.isValid() || alpha < 1.0) {
+ ma->alpha = alpha;
+ ma->mode |= MA_ZTRANSP | MA_TRANSP;
+ }
+ }
+ // texture
+ else if (ef->getOpacity().isTexture()) {
COLLADAFW::Texture ctex = ef->getOpacity().getTexture();
mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
if (mtex != NULL) {
@@ -930,22 +945,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
ma->mode |= MA_ZTRANSP | MA_TRANSP;
}
}
- // TRANSPARENT
- // color
-#if 0
- if (ef->getOpacity().isColor()) {
- // XXX don't know what to do here
- }
- // texture
- else if (ef->getOpacity().isTexture()) {
- ctex = ef->getOpacity().getTexture();
- if (mtex != NULL) mtex->mapto &= MAP_ALPHA;
- else {
- mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map);
- if (mtex != NULL) mtex->mapto = MAP_ALPHA;
- }
- }
-#endif
+
material_texture_mapping_map[ma] = texindex_texarray_map;
}
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 13dc1eda580..76b51148509 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -30,6 +30,7 @@
#include <set>
#include "COLLADASWEffectProfile.h"
+#include "COLLADAFWColorOrTexture.h"
#include "EffectExporter.h"
#include "DocumentExporter.h"
@@ -217,9 +218,9 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
// transparency
if (ma->mode & MA_TRANSP) {
// Tod: because we are in A_ONE mode transparency is calculated like this:
- ep.setTransparency(ma->alpha, false, "transparency");
- // cot = getcol(1.0f, 1.0f, 1.0f, 1.0f);
- // ep.setTransparent(cot);
+ cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha);
+ ep.setTransparent(cot);
+ ep.setOpaque(COLLADASW::EffectProfile::A_ONE);
}
// emission
diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp
index b271604f839..98aa85f8a9b 100644
--- a/source/blender/collada/ErrorHandler.cpp
+++ b/source/blender/collada/ErrorHandler.cpp
@@ -79,7 +79,7 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
COLLADASaxFWL::SaxFWLError *saxFWLError = (COLLADASaxFWL::SaxFWLError *) error;
/*
* Accept non critical errors as warnings (i.e. texture not found)
- * This makes the importer more gracefull, so it now imports what makes sense.
+ * This makes the importer more graceful, so it now imports what makes sense.
*/
if (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL) {
isError = false;
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index 649c86edd25..abe5130b9c1 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -539,8 +539,8 @@ void BoneExtended::set_bone_layers(std::string layerString, std::vector<std::str
}
/* If numeric layers and labeled layers are used in parallel (unlikely),
- we get a potential mixup. Just leave as is for now.
- */
+ * we get a potential mixup. Just leave as is for now.
+ */
this->bone_layers = bc_set_layer(this->bone_layers, pos);
}
diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp
index d6e5fdf86bb..caafdfe8f0c 100644
--- a/source/blender/compositor/operations/COM_MaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_MaskOperation.cpp
@@ -1,5 +1,4 @@
/*
-
* Copyright 2012, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 2d67ef1d584..a397b48e19c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -296,15 +296,16 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
Object *ob = base->object;
+ /* object itself */
+ build_object(scene, base, ob);
+
/* object that this is a proxy for */
// XXX: the way that proxies work needs to be completely reviewed!
if (ob->proxy) {
ob->proxy->proxy_from = ob;
+ build_object(scene, base, ob->proxy);
}
- /* object itself */
- build_object(scene, base, ob);
-
/* Object dupligroup. */
if (ob->dup_group) {
build_group(scene, base, ob->dup_group);
@@ -397,12 +398,12 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
{
if (ob->id.tag & LIB_TAG_DOIT) {
IDDepsNode *id_node = m_graph->find_id_node(&ob->id);
- id_node->layers = base->lay;
+ id_node->layers |= base->lay;
return;
}
IDDepsNode *id_node = add_id_node(&ob->id);
- id_node->layers = base->lay;
+ id_node->layers |= base->lay;
ob->customdata_mask = 0;
/* standard components */
@@ -441,7 +442,7 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
}
case OB_ARMATURE: /* Pose */
- if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) {
build_proxy_rig(ob);
}
else {
@@ -485,12 +486,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
if (ob->gpd) {
build_gpencil(ob->gpd);
}
-
- if (ob->proxy != NULL) {
- add_operation_node(&ob->id, DEPSNODE_TYPE_PROXY, DEPSOP_TYPE_POST,
- function_bind(BKE_object_eval_proxy_backlink, _1, ob),
- DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
- }
}
void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 34c661b21f3..42b8260c05a 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -266,18 +266,12 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
for (Base *base = (Base *)scene->base.first; base; base = base->next) {
Object *ob = base->object;
- /* Object that this is a proxy for.
- * Just makes sure backlink is correct.
- */
- if (ob->proxy) {
- ob->proxy->proxy_from = ob;
- }
-
/* object itself */
build_object(bmain, scene, ob);
/* object that this is a proxy for */
if (ob->proxy) {
+ ob->proxy->proxy_from = ob;
build_object(bmain, scene, ob->proxy);
/* TODO(sergey): This is an inverted relation, matches old depsgraph
* behavior and need to be investigated if it still need to be inverted.
@@ -441,7 +435,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o
}
case OB_ARMATURE: /* Pose */
- if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) {
build_proxy_rig(ob);
}
else {
@@ -926,6 +920,12 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
}
}
else {
+ if (dtar->id == id) {
+ /* Ignore input dependency if we're driving properties of the same ID,
+ * otherwise we'll be ending up in a cyclic dependency here.
+ */
+ continue;
+ }
/* resolve path to get node */
RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : "");
add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[RNA Target -> Driver]");
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index 9ba0b61a4f1..f9e1504b3ce 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -85,9 +85,6 @@ static void flush_init_func(void *data_v, int i)
id_node->done = 0;
comp_node->done = 0;
node->scheduled = false;
- if (comp_node->type == DEPSNODE_TYPE_PROXY) {
- node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- }
}
/* Flush updates from tagged nodes outwards until all affected nodes
diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc
index 12d5ee00a63..db807d22b89 100644
--- a/source/blender/depsgraph/intern/nodes/deg_node.cc
+++ b/source/blender/depsgraph/intern/nodes/deg_node.cc
@@ -181,6 +181,11 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
this->layers = (1 << 20) - 1;
this->eval_flags = 0;
+ /* For object we initialize layers to layer from base. */
+ if (GS(id) == ID_OB) {
+ this->layers = 0;
+ }
+
components = BLI_ghash_new(id_deps_node_hash_key,
id_deps_node_hash_key_cmp,
"Depsgraph id components hash");
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 6306926e0b2..6979a324b69 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -424,7 +424,9 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
for (curBone = bones->first; curBone; curBone = curBone->next) {
eBone = MEM_callocN(sizeof(EditBone), "make_editbone");
- /* Copy relevant data from bone to eBone */
+ /* Copy relevant data from bone to eBone
+ * Keep selection logic in sync with ED_armature_sync_selection.
+ */
eBone->parent = parent;
BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
eBone->flag = curBone->flag;
@@ -435,11 +437,11 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
eBone->flag |= BONE_TIPSEL;
if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
eBone->parent->flag |= BONE_TIPSEL;
- eBone->flag &= ~BONE_ROOTSEL; /* this is ignored when there is a connected parent, so unset it */
- }
- else {
- eBone->flag |= BONE_ROOTSEL;
}
+
+ /* For connected bones, take care when changing the selection when we have a connected parent,
+ * this flag is a copy of '(eBone->parent->flag & BONE_TIPSEL)'. */
+ eBone->flag |= BONE_ROOTSEL;
}
else {
/* if the bone is not selected, but connected to its parent
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 72b48a32477..e40dde24ce2 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -5843,7 +5843,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
normalize_v3(tan_r);
curve_fit_cubic_to_points_single_fl(
- points, points_len, dims, FLT_EPSILON,
+ points, points_len, NULL, dims, FLT_EPSILON,
tan_l, tan_r,
bezt_prev->vec[2], bezt_next->vec[0],
&error_sq_dummy);
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 38018541929..4d0a2fa53cd 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -55,6 +55,8 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
#define USE_SPLINE_FIT
#ifdef USE_SPLINE_FIT
@@ -65,6 +67,9 @@
#define STROKE_SAMPLE_DIST_MIN_PX 3
#define STROKE_SAMPLE_DIST_MAX_PX 6
+/* Distance between start/end points to consider cyclic */
+#define STROKE_CYCLIC_DIST_PX 8
+
/* -------------------------------------------------------------------- */
@@ -730,6 +735,11 @@ static void curve_draw_exec_precalc(wmOperator *op)
const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
PropertyRNA *prop;
+ prop = RNA_struct_find_property(op->ptr, "fit_method");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_enum_set(op->ptr, prop, cps->fit_method);
+ }
+
prop = RNA_struct_find_property(op->ptr, "corner_angle");
if (!RNA_property_is_set(op->ptr, prop)) {
const float corner_angle = (cps->flag & CURVE_PAINT_FLAG_CORNERS_DETECT) ? cps->corner_angle : (float)M_PI;
@@ -759,6 +769,32 @@ static void curve_draw_exec_precalc(wmOperator *op)
RNA_property_float_set(op->ptr, prop, error_threshold);
}
+ prop = RNA_struct_find_property(op->ptr, "use_cyclic");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ bool use_cyclic = false;
+
+ if (BLI_mempool_count(cdd->stroke_elem_pool) > 2) {
+ BLI_mempool_iter iter;
+ const struct StrokeElem *selem, *selem_first, *selem_last;
+
+ BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
+ selem_first = BLI_mempool_iterstep(&iter);
+ for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
+ selem_last = selem;
+ }
+
+ if (len_squared_v2v2(
+ selem_first->mval,
+ selem_last->mval) <= SQUARE(STROKE_CYCLIC_DIST_PX * U.pixelsize))
+ {
+ use_cyclic = true;
+ }
+ }
+
+ RNA_property_boolean_set(op->ptr, prop, use_cyclic);
+ }
+
+
if ((cps->radius_taper_start != 0.0f) ||
(cps->radius_taper_end != 0.0f))
{
@@ -868,8 +904,10 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
unsigned int cubic_spline_len = 0;
/* error in object local space */
+ const int fit_method = RNA_enum_get(op->ptr, "fit_method");
const float error_threshold = RNA_float_get(op->ptr, "error_threshold");
const float corner_angle = RNA_float_get(op->ptr, "corner_angle");
+ const bool use_cyclic = RNA_boolean_get(op->ptr, "use_cyclic");
{
BLI_mempool_iter iter;
@@ -894,14 +932,14 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
unsigned int *corners = NULL;
unsigned int corners_len = 0;
- if (corner_angle < (float)M_PI) {
+ if ((fit_method == CURVE_PAINT_FIT_METHOD_SPLIT) && (corner_angle < (float)M_PI)) {
/* this could be configurable... */
const float corner_radius_min = error_threshold / 8;
const float corner_radius_max = error_threshold * 2;
const unsigned int samples_max = 16;
curve_fit_corners_detect_fl(
- (const float *)coords, stroke_len, dims,
+ coords, stroke_len, dims,
corner_radius_min, corner_radius_max,
samples_max, corner_angle,
&corners, &corners_len);
@@ -909,13 +947,29 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
unsigned int *corners_index = NULL;
unsigned int corners_index_len = 0;
+ unsigned int calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
- const int result = curve_fit_cubic_to_points_fl(
- coords, stroke_len, dims, error_threshold, CURVE_FIT_CALC_HIGH_QUALIY,
- corners, corners_len,
- &cubic_spline, &cubic_spline_len,
- NULL,
- &corners_index, &corners_index_len);
+ if ((stroke_len > 2) && use_cyclic) {
+ calc_flag |= CURVE_FIT_CALC_CYCLIC;
+ }
+
+ int result;
+ if (fit_method == CURVE_PAINT_FIT_METHOD_REFIT) {
+ result = curve_fit_cubic_to_points_refit_fl(
+ coords, stroke_len, dims, error_threshold, calc_flag,
+ NULL, 0, corner_angle,
+ &cubic_spline, &cubic_spline_len,
+ NULL,
+ &corners_index, &corners_index_len);
+ }
+ else {
+ result = curve_fit_cubic_to_points_fl(
+ coords, stroke_len, dims, error_threshold, calc_flag,
+ corners, corners_len,
+ &cubic_spline, &cubic_spline_len,
+ NULL,
+ &corners_index, &corners_index_len);
+ }
MEM_freeN(coords);
if (corners) {
@@ -950,11 +1004,24 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
if (corners_index) {
/* ignore the first and last */
- for (unsigned int i = 1; i < corners_index_len - 1; i++) {
+ unsigned int i_start = 0, i_end = corners_index_len;
+
+ if ((corners_index_len >= 2) &&
+ (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0)
+ {
+ i_start += 1;
+ i_end -= 1;
+ }
+
+ for (unsigned int i = i_start; i < i_end; i++) {
bezt = &nu->bezt[corners_index[i]];
bezt->h1 = bezt->h2 = HD_FREE;
}
}
+
+ if (calc_flag & CURVE_FIT_CALC_CYCLIC) {
+ nu->flagu |= CU_NURB_CYCLIC;
+ }
}
if (corners_index) {
@@ -1220,13 +1287,19 @@ void CURVE_OT_draw(wmOperatorType *ot)
0.0001f, 10.0f);
RNA_def_property_ui_range(prop, 0.0, 10, 1, 4);
+ RNA_def_enum(ot->srna, "fit_method", rna_enum_curve_fit_method_items, CURVE_PAINT_FIT_METHOD_REFIT,
+ "Fit Method", "");
+
prop = RNA_def_float_distance(
ot->srna, "corner_angle", DEG2RADF(70.0f), 0.0f, M_PI, "Corner Angle", "", 0.0f, M_PI);
RNA_def_property_subtype(prop, PROP_ANGLE);
- prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ prop = RNA_def_boolean(ot->srna, "use_cyclic", true, "Cyclic", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index a29266294b4..cad70443657 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -294,11 +294,11 @@ static void select_adjacent_cp(
if (next < 0) bezt = &nu->bezt[a - 1];
while (a--) {
if (a - abs(next) < 0) break;
- if ((lastsel == 0) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
+ if ((lastsel == false) && (bezt->hide == 0) && ((bezt->f2 & SELECT) || (selstatus == DESELECT))) {
bezt += next;
if (!(bezt->f2 & SELECT) || (selstatus == DESELECT)) {
- short sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
- if ((sel == 1) && (cont == 0)) lastsel = true;
+ bool sel = select_beztriple(bezt, selstatus, SELECT, VISIBLE);
+ if (sel && !cont) lastsel = true;
}
}
else {
@@ -315,11 +315,11 @@ static void select_adjacent_cp(
if (next < 0) bp = &nu->bp[a - 1];
while (a--) {
if (a - abs(next) < 0) break;
- if ((lastsel == 0) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
+ if ((lastsel == false) && (bp->hide == 0) && ((bp->f1 & SELECT) || (selstatus == DESELECT))) {
bp += next;
if (!(bp->f1 & SELECT) || (selstatus == DESELECT)) {
- short sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
- if ((sel == 1) && (cont == 0)) lastsel = true;
+ bool sel = select_bpoint(bp, selstatus, SELECT, VISIBLE);
+ if (sel && !cont) lastsel = true;
}
}
else {
@@ -820,7 +820,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
BezTriple *bezt;
int a;
int sel = 0;
- short lastsel = false;
+ bool lastsel = false;
if (obedit->type == OB_SURF) {
for (nu = editnurb->first; nu; nu = nu->next) {
@@ -935,9 +935,8 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
a = nu->pntsu * nu->pntsv;
bp = nu->bp;
while (a--) {
- if ((lastsel == 0) && (bp->hide == 0) && (bp->f1 & SELECT)) {
- if (lastsel != 0) sel = 1;
- else sel = 0;
+ if ((lastsel == false) && (bp->hide == 0) && (bp->f1 & SELECT)) {
+ sel = 0;
/* first and last are exceptions */
if (a == nu->pntsu * nu->pntsv - 1) {
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 053a7ee5023..b40b51e337f 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -1695,7 +1695,7 @@ static int font_open_exec(bContext *C, wmOperator *op)
if (pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&font->id);
RNA_id_pointer_create(&font->id, &idptr);
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 81e2558e765..602e203a381 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -325,18 +325,18 @@ bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool
/* Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
* are defined in DNA_userdef_types.h
- * - Scene settings take presidence over those for userprefs, with old files
+ * - Scene settings take precedence over those for userprefs, with old files
* inheriting userpref settings for the scene settings
* - "On/Off + Mode" are stored per Scene, but "settings" are currently stored
* as userprefs
*/
/* Auto-Keying macros for use by various tools */
-/* check if auto-keyframing is enabled (per scene takes presidence) */
+/* check if auto-keyframing is enabled (per scene takes precedence) */
#define IS_AUTOKEY_ON(scene) ((scene) ? (scene->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
-/* check the mode for auto-keyframing (per scene takes presidence) */
+/* check the mode for auto-keyframing (per scene takes precedence) */
#define IS_AUTOKEY_MODE(scene, mode) ((scene) ? (scene->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : (U.autokey_mode == AUTOKEY_MODE_##mode))
-/* check if a flag is set for auto-keyframing (per scene takes presidence) */
+/* check if a flag is set for auto-keyframing (per scene takes precedence) */
#define IS_AUTOKEY_FLAG(scene, flag) \
((scene) ? \
((scene->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || (U.autokey_flag & AUTOKEY_FLAG_##flag)) \
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index b09284aa759..48c1e2d1996 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -208,6 +208,7 @@ eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const fl
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag);
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
+bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]);
bool ED_view3d_win_to_ray(
const struct ARegion *ar, const struct View3D *v3d, const float mval[2],
float ray_start[3], float ray_normal[3], const bool do_clip);
@@ -218,6 +219,7 @@ void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coo
void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]);
void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]);
void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac);
+void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]);
void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]);
bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
float r_ray_start[3], float r_ray_end[3], const bool do_clip);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index ba7240be5d8..cbe8654ceb6 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1138,7 +1138,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
* as new items are added to the menu later on. It also optimises efficiency -
* a radial menu is best kept symmetrical, with as large an angle between
* items as possible, so that the gestural mouse movements can be fast and inexact.
-
+ *
* It starts off with two opposite sides for the first two items
* then joined by the one below for the third (this way, even with three items,
* the menu seems to still be 'in order' reading left to right). Then the fourth is
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 72a6a04feec..9ce863dc8f7 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -734,24 +734,50 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
CLAMP(max, rect.ymin, rect.ymax);
fdrawline(rect.xmax - 3, min, rect.xmax - 3, max);
}
+ /* RGB (3 channel) */
+ else if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB) {
+ glBlendFunc(GL_ONE, GL_ONE);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ glPushMatrix();
+
+ glTranslatef(rect.xmin, yofs, 0.f);
+ glScalef(w, h, 0.f);
+
+ glColor3fv( colors_alpha[0] );
+ glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1);
+ glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
+
+ glColor3fv( colors_alpha[1] );
+ glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2);
+ glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
- /* RGB / YCC (3 channels) */
+ glColor3fv( colors_alpha[2] );
+ glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3);
+ glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glPopMatrix();
+ }
+ /* PARADE / YCC (3 channels) */
else if (ELEM(scopes->wavefrm_mode,
- SCOPES_WAVEFRM_RGB,
+ SCOPES_WAVEFRM_RGB_PARADE,
SCOPES_WAVEFRM_YCC_601,
SCOPES_WAVEFRM_YCC_709,
- SCOPES_WAVEFRM_YCC_JPEG))
+ SCOPES_WAVEFRM_YCC_JPEG
+ ))
{
- int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB);
-
+ int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB_PARADE);
+
glBlendFunc(GL_ONE, GL_ONE);
-
+
glPushMatrix();
glEnableClientState(GL_VERTEX_ARRAY);
-
+
glTranslatef(rect.xmin, yofs, 0.f);
glScalef(w3, h, 0.f);
-
+
glColor3fv((rgb) ? colors_alpha[0] : colorsycc_alpha[0]);
glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1);
glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
@@ -760,19 +786,19 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
glColor3fv((rgb) ? colors_alpha[1] : colorsycc_alpha[1]);
glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2);
glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
+
glTranslatef(1.f, 0.f, 0.f);
glColor3fv((rgb) ? colors_alpha[2] : colorsycc_alpha[2]);
glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3);
glDrawArrays(GL_POINTS, 0, scopes->waveform_tot);
-
+
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
-
-
- /* min max */
+ }
+ /* min max */
+ if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA ) {
for (int c = 0; c < 3; c++) {
- if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB)
+ if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_RGB_PARADE, SCOPES_WAVEFRM_RGB))
glColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f);
else
glColor3f(colorsycc[c][0] * 0.75f, colorsycc[c][1] * 0.75f, colorsycc[c][2] * 0.75f);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 0a0ecf93d17..11703208b2a 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1057,7 +1057,9 @@ static void ui_multibut_free(uiHandleButtonData *data, uiBlock *block)
}
}
-static bool ui_multibut_states_tag(uiBut *but_active, uiHandleButtonData *data, const wmEvent *event)
+static bool ui_multibut_states_tag(
+ uiBut *but_active,
+ uiHandleButtonData *data, const wmEvent *event)
{
uiBut *but;
float seg[2][2];
@@ -1668,7 +1670,9 @@ static bool ui_but_contains_point_px_icon(uiBut *but, ARegion *ar, const wmEvent
return BLI_rcti_isect_pt(&rect, x, y);
}
-static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static bool ui_but_drag_init(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
/* prevent other WM gestures to start while we try to drag */
WM_gestures_remove(C);
@@ -1740,11 +1744,16 @@ static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data,
}
}
else {
- wmDrag *drag;
+ wmDrag *drag = WM_event_start_drag(
+ C, but->icon, but->dragtype, but->dragpoin,
+ ui_but_value_get(but), WM_DRAG_NOP);
- drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_but_value_get(but), WM_DRAG_NOP);
- if (but->imb)
- WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect));
+ if (but->imb) {
+ WM_event_drag_image(
+ drag, but->imb, but->imb_scale,
+ BLI_rctf_size_x(&but->rect),
+ BLI_rctf_size_y(&but->rect));
+ }
}
return true;
}
@@ -1872,11 +1881,15 @@ static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to)
/* (3) add a new controller */
if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, &props_ptr) & OPERATOR_FINISHED) {
cont = (bController *)ob->controllers.last;
- cont->type = CONT_LOGIC_AND; /* Quick fix to make sure we always have an AND controller. It might be nicer to make sure the operator gives us the right one though... */
+ /* Quick fix to make sure we always have an AND controller.
+ * It might be nicer to make sure the operator gives us the right one though... */
+ cont->type = CONT_LOGIC_AND;
/* (4) link the sensor->controller->actuator */
tmp_but = MEM_callocN(sizeof(uiBut), "uiBut");
- UI_but_link_set(tmp_but, (void **)&cont, (void ***)&(cont->links), &(cont->totlinks), from->link->tocode, (int)to->hardmin);
+ UI_but_link_set(
+ tmp_but, (void **)&cont, (void ***)&(cont->links),
+ &cont->totlinks, from->link->tocode, (int)to->hardmin);
tmp_but->hardmin = from->link->tocode;
tmp_but->poin = (char *)cont;
@@ -3180,7 +3193,9 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
-static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static void ui_do_but_textedit(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int retval = WM_UI_HANDLER_CONTINUE;
bool changed = false, inbox = false, update = false;
@@ -3233,7 +3248,8 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
if (data->searchbox)
inbox = ui_searchbox_inside(data->searchbox, event->x, event->y);
- /* for double click: we do a press again for when you first click on button (selects all text, no cursor pos) */
+ /* for double click: we do a press again for when you first click on button
+ * (selects all text, no cursor pos) */
if (event->val == KM_PRESS || event->val == KM_DBL_CLICK) {
float mx, my;
@@ -3477,7 +3493,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
ED_region_tag_redraw(data->region);
}
-static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static void ui_do_but_textedit_select(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my, retval = WM_UI_HANDLER_CONTINUE;
@@ -3682,7 +3700,9 @@ static uiBut *ui_but_list_row_text_activate(
/* ***************** events for different button types *************** */
-static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_BUT(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
@@ -3713,7 +3733,9 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_HOTKEYEVT(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
@@ -3776,7 +3798,9 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_KEYEVT(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
@@ -3802,7 +3826,9 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_TEX(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
@@ -3830,7 +3856,9 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_SEARCH_UNLINK(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
uiButExtraIconType extra_icon_type;
@@ -3877,7 +3905,9 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa
return ui_do_but_TEX(C, block, but, data, event);
}
-static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_TOG(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
#ifdef USE_DRAG_TOGGLE
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -3944,7 +3974,9 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_EXIT(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -4092,7 +4124,7 @@ static float ui_numedit_apply_snap(
static bool ui_numedit_but_NUM(
uiBut *but, uiHandleButtonData *data,
- int mx,
+ int mx, const bool is_motion,
const enum eSnapType snap, float fac)
{
float deler, tempf, softmin, softmax, softrange;
@@ -4100,8 +4132,10 @@ static bool ui_numedit_but_NUM(
bool changed = false;
const bool is_float = ui_but_is_float(but);
- /* prevent unwanted drag adjustments */
- if (ui_but_dragedit_update_mval(data, mx) == false) {
+ /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */
+ if ((is_motion || data->draglock) &&
+ (ui_but_dragedit_update_mval(data, mx) == false))
+ {
return changed;
}
@@ -4242,7 +4276,9 @@ static bool ui_numedit_but_NUM(
return changed;
}
-static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_NUM(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my; /* mouse location scaled to fit the UI */
int screen_mx, screen_my; /* mouse location kept at screen pixel coords */
@@ -4324,6 +4360,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
}
}
else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ const bool is_motion = (event->type == MOUSEMOVE);
const enum eSnapType snap = ui_event_to_snap(event);
float fac;
@@ -4335,8 +4372,9 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
fac = 1.0f;
if (event->shift) fac /= 10.0f;
- if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), snap, fac))
+ if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), is_motion, snap, fac)) {
ui_numedit_apply(C, block, but, data);
+ }
#ifdef USE_DRAG_MULTINUM
else if (data->multi_data.has_mbuts) {
if (data->multi_data.init == BUTTON_MULTI_INIT_ENABLE) {
@@ -4430,7 +4468,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
static bool ui_numedit_but_SLI(
uiBut *but, uiHandleButtonData *data,
- int mx, const bool is_horizontal,
+ int mx, const bool is_horizontal, const bool is_motion,
const bool snap, const bool shift)
{
float deler, f, tempf, softmin, softmax, softrange;
@@ -4440,8 +4478,9 @@ static bool ui_numedit_but_SLI(
/* note, 'offs' is really from the widget drawing rounded corners see 'widget_numslider' */
float offs;
- /* prevent unwanted drag adjustments */
+ /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */
if ((but->type != UI_BTYPE_SCROLL) &&
+ (is_motion || data->draglock) &&
(ui_but_dragedit_update_mval(data, mx) == false))
{
return changed;
@@ -4541,7 +4580,9 @@ static bool ui_numedit_but_SLI(
return changed;
}
-static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_SLI(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my, click = 0;
int retval = WM_UI_HANDLER_CONTINUE;
@@ -4634,12 +4675,14 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
}
}
else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ const bool is_motion = (event->type == MOUSEMOVE);
#ifdef USE_DRAG_MULTINUM
data->multi_data.drag_dir[0] += abs(data->draglastx - mx);
data->multi_data.drag_dir[1] += abs(data->draglasty - my);
#endif
- if (ui_numedit_but_SLI(but, data, mx, true, event->ctrl != 0, event->shift != 0))
+ if (ui_numedit_but_SLI(but, data, mx, true, is_motion, event->ctrl != 0, event->shift != 0)) {
ui_numedit_apply(C, block, but, data);
+ }
#ifdef USE_DRAG_MULTINUM
else if (data->multi_data.has_mbuts) {
@@ -4722,7 +4765,9 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
return retval;
}
-static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_SCROLL(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my /*, click = 0 */;
int retval = WM_UI_HANDLER_CONTINUE;
@@ -4765,8 +4810,10 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else if (event->type == MOUSEMOVE) {
- if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, false, false))
+ const bool is_motion = (event->type == MOUSEMOVE);
+ if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, is_motion, false, false)) {
ui_numedit_apply(C, block, but, data);
+ }
}
retval = WM_UI_HANDLER_BREAK;
@@ -4775,7 +4822,9 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut
return retval;
}
-static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_GRIP(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
int retval = WM_UI_HANDLER_CONTINUE;
@@ -4826,7 +4875,9 @@ static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButto
return retval;
}
-static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_LISTROW(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* hack to pass on ctrl+click and double click to overlapping text
@@ -4846,7 +4897,9 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data,
return ui_do_but_EXIT(C, but, data, event);
}
-static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_BLOCK(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
@@ -5021,7 +5074,9 @@ static void ui_palette_set_active(uiBut *but)
}
}
-static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_COLOR(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* first handle click on icondrag type button */
@@ -5154,7 +5209,9 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_UNITVEC(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_UNITVEC(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -5431,7 +5488,9 @@ static void ui_ndofedit_but_HSVCUBE(
ui_but_v3_set(but, data->vec);
}
-static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_HSVCUBE(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -5693,7 +5752,9 @@ static void ui_ndofedit_but_HSVCIRCLE(
}
-static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_HSVCIRCLE(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->color_data;
@@ -5821,7 +5882,9 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m
return changed;
}
-static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_COLORBAND(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
ColorBand *coba;
CBData *cbd;
@@ -5997,7 +6060,9 @@ static bool ui_numedit_but_CURVE(
return changed;
}
-static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_CURVE(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my, a;
bool changed = false;
@@ -6165,7 +6230,9 @@ static bool ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int m
return changed;
}
-static int ui_do_but_HISTOGRAM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_HISTOGRAM(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -6238,7 +6305,9 @@ static bool ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx
return changed;
}
-static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_WAVEFORM(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -6292,7 +6361,9 @@ static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleB
return WM_UI_HANDLER_CONTINUE;
}
-static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_LINK(
+ bContext *C, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
VECCOPY2D(but->linkto, event->mval);
@@ -6355,7 +6426,9 @@ static bool ui_numedit_but_TRACKPREVIEW(
return changed;
}
-static int ui_do_but_TRACKPREVIEW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
+static int ui_do_but_TRACKPREVIEW(
+ bContext *C, uiBlock *block, uiBut *but,
+ uiHandleButtonData *data, const wmEvent *event)
{
int mx, my;
@@ -6851,7 +6924,8 @@ static bool ui_but_menu(bContext *C, uiBut *but)
WM_operator_properties_create(&ptr_props, "WM_OT_doc_view");
RNA_string_set(&ptr_props, "doc_id", buf);
- uiItemFullO(layout, "WM_OT_doc_view", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
+ uiItemFullO(layout, "WM_OT_doc_view",
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"),
ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0);
/* XXX inactive option, not for public! */
@@ -6860,7 +6934,8 @@ static bool ui_but_menu(bContext *C, uiBut *but)
RNA_string_set(&ptr_props, "doc_id", buf);
RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop));
- uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
+ uiItemFullO(layout, "WM_OT_doc_edit",
+ "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0);
#endif
}
}
@@ -7440,7 +7515,8 @@ static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y)
/**
* Can we mouse over the button or is it hidden/disabled/layout.
- * Note: ctrl is kind of a hack currently, so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
+ * \note ctrl is kind of a hack currently,
+ * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed.
*/
static bool ui_but_is_interactive(const uiBut *but, const bool labeledit)
{
@@ -7634,7 +7710,9 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
if (but->block->auto_open == true) { /* test for toolbox */
time = 1;
}
- else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) || but->block->auto_open == true) {
+ else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) ||
+ (but->block->auto_open == true))
+ {
time = 5 * U.menuthreshold2;
}
else if (U.uiflag & USER_MENUOPENAUTO) {
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index e00d8cf7c07..4107414a240 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1061,6 +1061,9 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
}
}
+static void ui_id_preview_image_render_size(
+ const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job);
+
void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big)
{
Icon *icon = BKE_icon_get(icon_id);
@@ -1076,22 +1079,20 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi
}
if (di) {
- if (di->type == ICON_TYPE_PREVIEW) {
- PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj;
-
- if (prv) {
- const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON;
-
- if (!prv->use_deferred || prv->rect[size] || (prv->flag[size] & PRV_USER_EDITED)) {
- return;
+ switch (di->type) {
+ case ICON_TYPE_PREVIEW:
+ {
+ ID *id = (icon->type != 0) ? icon->obj : NULL;
+ PreviewImage *prv = id ? BKE_previewimg_id_ensure(id) : icon->obj;
+
+ if (prv) {
+ const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON;
+
+ if (id || prv->use_deferred) {
+ ui_id_preview_image_render_size(C, NULL, id, prv, size, true);
+ }
}
-
- icon_create_rect(prv, size);
-
- /* Always using job (background) version. */
- ED_preview_icon_job(C, prv, NULL, prv->rect[size], prv->w[size], prv->h[size]);
-
- prv->flag[size] &= ~PRV_CHANGED;
+ break;
}
}
}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 01b10b7b032..1af6d902b18 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -416,7 +416,7 @@ bool UI_context_copy_to_selected_list(
if ((id_data == NULL) ||
(id_data->tag & LIB_TAG_DOIT) == 0 ||
- ID_IS_LINKED_DATABLOCK(id_data->lib) ||
+ ID_IS_LINKED_DATABLOCK(id_data) ||
(GS(id_data->name) != id_code))
{
BLI_remlink(&lb, link);
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 575b32e81e8..694794193da 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -110,7 +110,7 @@ bool ui_but_menu_step_poll(const uiBut *but)
{
BLI_assert(but->type == UI_BTYPE_MENU);
- /* currenly only RNA buttons */
+ /* currently only RNA buttons */
return ((but->menu_step_func != NULL) ||
(but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM));
}
@@ -459,6 +459,11 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
data->totline++;
}
+ else if (ID_IS_LINKED_DATAPATH(id)) {
+ BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Using file path as asset"));
+ data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
+ data->totline++;
+ }
}
}
else if (but->optype) {
@@ -3331,6 +3336,11 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
if (win) {
UI_popup_handlers_remove(&win->modalhandlers, block->handle);
ui_popup_block_free(C, block->handle);
+
+ /* In the case we have nested popups, closing one may need to redraw anorher, see: T48874 */
+ for (ARegion *ar = win->screen->regionbase.first; ar; ar = ar->next) {
+ ED_region_tag_refresh_ui(ar);
+ }
}
}
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index d91bd498225..aec4065adaf 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -302,7 +302,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_LOCAL:
if (id) {
- if (id_make_local(CTX_data_main(C), id, false)) {
+ if (id_make_local(CTX_data_main(C), id, false, false)) {
/* reassign to get get proper updates/notifiers */
idptr = RNA_property_pointer_get(&template->ptr, template->prop);
RNA_property_pointer_set(&template->ptr, template->prop, idptr);
@@ -455,7 +455,7 @@ static void template_ID(
else {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Direct linked library datablock, click to make local"));
- if (!id_make_local(CTX_data_main(C), id, true /* test */) || (idfrom && idfrom->lib))
+ if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib))
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index b74c4b5f526..d62651cef81 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -175,7 +175,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
open_sim);
if (export_count == 0) {
- BKE_report(op->reports, RPT_WARNING, "Export file is empty");
+ BKE_report(op->reports, RPT_WARNING, "No objects selected -- Created empty export file");
return OPERATOR_CANCELLED;
}
else if (export_count < 0) {
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 69588928253..281a8b2a02d 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -563,7 +563,7 @@ static BMEdge *bm_face_split_edge_find(
if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) ||
BM_edge_exists(v_pivot, l_iter->e->v2)))
{
- /* very unlikley but will cause complications splicing the verts together,
+ /* very unlikely but will cause complications splicing the verts together,
* so just skip this case */
ok = false;
}
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index e3e5863dc0e..e31e4096ded 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -395,7 +395,7 @@ static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs,
* return an un-ordered array of loop pairs
* use for rebuilding face-fill
*
- * \note the method currenly used fails for edges with 3+ face users and gives
+ * \note the method currently used fails for edges with 3+ face users and gives
* nasty holes in the mesh, there isnt a good way of knowing ahead of time
* which loops will be split apart (its possible to figure out but quite involved).
* So for now this is a known limitation of current rip-fill option.
@@ -748,10 +748,8 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
}
if (do_fill) {
- if (do_fill) {
- /* match extrude vert-order */
- BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
- }
+ /* match extrude vert-order */
+ BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
}
MEM_freeN(vout);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 3a7a8fb883b..1a14fad8650 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -4032,7 +4032,7 @@ static int edbm_decimate_exec(bContext *C, wmOperator *op)
const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset);
weight = defvert_find_weight(dv, defbase_act);
if (invert_vertex_group) {
- weight = 1.0 - weight;
+ weight = 1.0f - weight;
}
}
else {
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index bcdd170c53c..0fe43c44d7d 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -440,7 +440,7 @@ static int group_link_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* Early return check, if the object is already in group
- * we could sckip all the dependency check and just consider
+ * we could skip all the dependency check and just consider
* operator is finished.
*/
if (BKE_group_object_exists(group, ob)) {
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 6b16e19f790..b3edf1f5e0d 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2104,11 +2104,11 @@ static void make_local_makelocalmaterial(Material *ma)
AnimData *adt;
int b;
- id_make_local(G.main, &ma->id, false);
+ id_make_local(G.main, &ma->id, false, false);
for (b = 0; b < MAX_MTEX; b++)
if (ma->mtex[b] && ma->mtex[b]->tex)
- id_make_local(G.main, &ma->mtex[b]->tex->id, false);
+ id_make_local(G.main, &ma->mtex[b]->tex->id, false, false);
adt = BKE_animdata_from_id(&ma->id);
if (adt) BKE_animdata_make_local(adt);
@@ -2237,7 +2237,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
if (ob->id.lib)
- id_make_local(bmain, &ob->id, false);
+ id_make_local(bmain, &ob->id, false, false);
}
CTX_DATA_END;
@@ -2259,7 +2259,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
id = ob->data;
if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
- id_make_local(bmain, id, false);
+ id_make_local(bmain, id, false, false);
adt = BKE_animdata_from_id(id);
if (adt) BKE_animdata_make_local(adt);
@@ -2275,7 +2275,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
for (psys = ob->particlesystem.first; psys; psys = psys->next)
- id_make_local(bmain, &psys->part->id, false);
+ id_make_local(bmain, &psys->part->id, false, false);
adt = BKE_animdata_from_id(&ob->id);
if (adt) BKE_animdata_make_local(adt);
@@ -2294,7 +2294,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
for (b = 0; b < MAX_MTEX; b++)
if (la->mtex[b] && la->mtex[b]->tex)
- id_make_local(bmain, &la->mtex[b]->tex->id, false);
+ id_make_local(bmain, &la->mtex[b]->tex->id, false, false);
}
else {
for (a = 0; a < ob->totcol; a++) {
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 0cbbe46f461..f1b7186f8a1 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -577,7 +577,6 @@ static bool select_grouped_parent(bContext *C) /* Makes parent active and de-sel
/* can be NULL if parent in other scene */
if (baspar && BASE_SELECTABLE(v3d, baspar)) {
- ED_base_object_select(basact, BA_DESELECT);
ED_base_object_select(baspar, BA_SELECT);
ED_base_object_activate(C, baspar);
changed = true;
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 6e8aaebcccc..ad41fb23a69 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -3538,8 +3538,10 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
return BLI_natstrcmp(def_a->name, def_b->name);
}
-/* Sorts the weight groups according to the bone hierarchy of the
- associated armature (similar to how bones are ordered in the Outliner) */
+/**
+ * Sorts the weight groups according to the bone hierarchy of the
+ * associated armature (similar to how bones are ordered in the Outliner)
+ */
static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
{
if (bonebase == NULL) {
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 1203889cf0e..8c5d25ad44d 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -1482,7 +1482,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
void render_view3d_update(RenderEngine *engine, const bContext *C)
{
/* this shouldn't be needed and causes too many database rebuilds, but we
- * aren't actually tracking updates for all relevent datablocks so this is
+ * aren't actually tracking updates for all relevant datablocks so this is
* a catch-all for updates */
engine->update_flag |= RE_ENGINE_UPDATE_DATABASE;
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index c3f83138707..5a0c250c777 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -102,7 +102,7 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
if (!ob)
return OPERATOR_CANCELLED;
- object_add_material_slot(ob);
+ BKE_object_material_slot_add(ob);
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
@@ -145,7 +145,7 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- object_remove_material_slot(ob);
+ BKE_object_material_slot_remove(ob);
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
@@ -529,7 +529,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&tex->id);
if (ptr.id.data && GS(((ID *)ptr.id.data)->name) == ID_MA &&
@@ -592,7 +592,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&wo->id);
RNA_id_pointer_create(&wo->id, &idptr);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index ab8b7d4e138..8d058ed2081 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -580,15 +580,20 @@ void ED_region_tag_refresh_ui(ARegion *ar)
void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct)
{
if (ar && !(ar->do_draw & RGN_DRAWING)) {
- if (!(ar->do_draw & RGN_DRAW)) {
+ if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_PARTIAL))) {
/* no redraw set yet, set partial region */
ar->do_draw |= RGN_DRAW_PARTIAL;
ar->drawrct = *rct;
}
else if (ar->drawrct.xmin != ar->drawrct.xmax) {
+ BLI_assert((ar->do_draw & RGN_DRAW_PARTIAL) != 0);
/* partial redraw already set, expand region */
BLI_rcti_union(&ar->drawrct, rct);
}
+ else {
+ BLI_assert((ar->do_draw & RGN_DRAW) != 0);
+ /* Else, full redraw is already requested, nothing to do here. */
+ }
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 6ed969cb270..d60c8e8dbd9 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -183,8 +183,8 @@ BLI_INLINE unsigned char f_to_char(const float val)
/* to avoid locking in tile initialization */
#define TILE_PENDING SET_INT_IN_POINTER(-1)
-/* This is mainly a convenience struct used so we can keep an array of images we use
- * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread
+/* This is mainly a convenience struct used so we can keep an array of images we use -
+ * their imbufs, etc, in 1 array, When using threads this array is copied for each thread
* because 'partRedrawRect' and 'touch' values would not be thread safe */
typedef struct ProjPaintImage {
Image *ima;
@@ -202,7 +202,7 @@ typedef struct ProjPaintImage {
*/
typedef struct ProjStrokeHandle {
/* Support for painting from multiple views at once,
- * currently used to impliment symmetry painting,
+ * currently used to implement symmetry painting,
* we can assume at least the first is set while painting. */
struct ProjPaintState *ps_views[8];
int ps_views_tot;
@@ -2174,7 +2174,7 @@ static void project_bucket_clip_face(
if ((*tot) < 3) {
/* no intersections to speak of, but more probable is that all face is just outside the
- * rectangle and culled due to float precision issues. Since above teste have failed,
+ * rectangle and culled due to float precision issues. Since above tests have failed,
* just dump triangle as is for painting */
*tot = 0;
copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++;
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index aa17cb02fe5..1431958501d 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -491,31 +491,30 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
}
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
-static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outpressure,
- const PaintSample *sample, PaintMode mode)
+static bool paint_smooth_stroke(
+ PaintStroke *stroke, const PaintSample *sample, PaintMode mode,
+ float r_mouse[2], float *r_pressure)
{
if (paint_supports_smooth_stroke(stroke->brush, mode)) {
float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
- float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u;
- float dx = stroke->last_mouse_position[0] - sample->mouse[0];
- float dy = stroke->last_mouse_position[1] - sample->mouse[1];
+ float u = stroke->brush->smooth_stroke_factor;
/* If the mouse is moving within the radius of the last move,
* don't update the mouse position. This allows sharp turns. */
- if (dx * dx + dy * dy < radius * radius)
- return 0;
+ if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < SQUARE(radius)) {
+ return false;
+ }
- output[0] = sample->mouse[0] * v + stroke->last_mouse_position[0] * u;
- output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u;
- *outpressure = sample->pressure * v + stroke->last_pressure * u;
+ interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u);
+ *r_pressure = interpf(sample->pressure, stroke->last_pressure, u);
}
else {
- output[0] = sample->mouse[0];
- output[1] = sample->mouse[1];
- *outpressure = sample->pressure;
+ r_mouse[0] = sample->mouse[0];
+ r_mouse[1] = sample->mouse[1];
+ *r_pressure = sample->pressure;
}
- return 1;
+ return true;
}
static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure)
@@ -1190,7 +1189,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* airbrush */
((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer))
{
- if (paint_smooth_stroke(stroke, mouse, &pressure, &sample_average, mode)) {
+ if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) {
if (stroke->stroke_started) {
if (paint_space_stroke_enabled(br, mode)) {
if (paint_space_stroke(C, op, mouse, pressure))
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 3bcd610150c..991025a4d5d 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -257,9 +257,7 @@ static bool make_vertexcol(Object *ob) /* single ob */
/* copies from shadedisplist to mcol */
if (!me->mloopcol && me->totloop) {
- if (!me->mloopcol) {
- CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
- }
+ CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
BKE_mesh_update_customdata_pointers(me, true);
}
@@ -2380,9 +2378,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
swap_m4m4(vc->rv3d->persmat, mat);
/* calculate pivot for rotation around seletion if needed */
- if (U.uiflag & USER_ORBIT_SELECTION) {
- paint_last_stroke_update(scene, vc->ar, mval);
- }
+ /* also needed for "View Selected" on last stroke */
+ paint_last_stroke_update(scene, vc->ar, mval);
DAG_id_tag_update(ob->data, 0);
ED_region_tag_redraw(vc->ar);
@@ -2858,9 +2855,8 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
}
/* calculate pivot for rotation around seletion if needed */
- if (U.uiflag & USER_ORBIT_SELECTION) {
- paint_last_stroke_update(scene, vc->ar, mval);
- }
+ /* also needed for "View Selected" on last stroke */
+ paint_last_stroke_update(scene, vc->ar, mval);
ED_region_tag_redraw(vc->ar);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index cc7531b9783..1305b76b5ad 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1145,7 +1145,9 @@ static void calc_area_normal_and_center(
/* Return modified brush strength. Includes the direction of the brush, positive
* values pull vertices, negative values push. Uses tablet pressure and a
* special multiplier found experimentally to scale the strength factor. */
-static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups)
+static float brush_strength(
+ const Sculpt *sd, const StrokeCache *cache,
+ const float feather, const UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
const Brush *brush = BKE_paint_brush((Paint *)&sd->paint);
@@ -3985,7 +3987,9 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
}
/* Initialize the stroke cache invariants from operator properties */
-static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
+static void sculpt_update_cache_invariants(
+ bContext *C, Sculpt *sd, SculptSession *ss,
+ wmOperator *op, const float mouse[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
Scene *scene = CTX_data_scene(C);
@@ -4448,7 +4452,9 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
}
}
-static float sculpt_raycast_init(ViewContext *vc, const float mouse[2], float ray_start[3], float ray_end[3], float ray_normal[3], bool original)
+static float sculpt_raycast_init(
+ ViewContext *vc, const float mouse[2],
+ float ray_start[3], float ray_end[3], float ray_normal[3], bool original)
{
float obimat[4][4];
float dist;
@@ -4956,8 +4962,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss)
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
}
- ss->cd_vert_node_offset = CustomData_get_n_offset(&ss->bm->vdata, CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
+ ss->cd_vert_node_offset = CustomData_get_n_offset(
+ &ss->bm->vdata, CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
@@ -4967,8 +4974,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss)
cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
}
- ss->cd_face_node_offset = CustomData_get_n_offset(&ss->bm->pdata, CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
+ ss->cd_face_node_offset = CustomData_get_n_offset(
+ &ss->bm->pdata, CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
}
@@ -5667,7 +5675,8 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, "Location", "Screen Coordinates of sampling", 0, SHRT_MAX);
+ RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
+ "Location", "Screen Coordinates of sampling", 0, SHRT_MAX);
}
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 4931426d62e..03f2e146b7d 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -136,7 +136,7 @@ static int sound_open_exec(bContext *C, wmOperator *op)
if (pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&sound->id);
RNA_id_pointer_create(&sound->id, &idptr);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 1ff656243d6..14d0f909d23 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -634,7 +634,7 @@ typedef struct PrefetchQueue {
short render_size, render_flag;
/* If true prefecthing goes forward in time,
- * othwewise it goes backwards in time (starting from current frame).
+ * otherwise it goes backwards in time (starting from current frame).
*/
bool forward;
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 085fdd57309..83876ae2669 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -234,7 +234,7 @@ static int open_exec(bContext *C, wmOperator *op)
if (pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&clip->id);
RNA_id_pointer_create(&clip->id, &idptr);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 6d1916cfae7..6fb55729802 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -40,7 +40,7 @@
#include "BLO_readfile.h"
#include "BKE_appdir.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 8e2eed89de2..814eb846d37 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -65,7 +65,7 @@
#include "RNA_types.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_library.h"
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index cd008d4a54b..ee768ba6087 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -37,7 +37,7 @@
extern "C" {
#endif
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
struct AssetEngineType;
struct AssetEngine;
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 9f5fffc73c5..7e230b5befb 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -43,7 +43,7 @@
#include "RNA_types.h"
#include "BKE_appdir.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_global.h"
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index b837e516422..ae91a466495 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -826,7 +826,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
//if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
// return;
- /* No curve to modify/visualise the result?
+ /* No curve to modify/visualize the result?
* => We still want to show the 1-1 default...
*/
if ((fcu->totvert == 0) && BLI_listbase_is_empty(&fcu->modifiers)) {
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index a2db6827b0e..38a54ade367 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -345,6 +345,13 @@ struct ImageUI_Data {
int rpass_index;
};
+static struct ImageUI_Data *ui_imageuser_data_copy(const struct ImageUI_Data *rnd_pt_src)
+{
+ struct ImageUI_Data *rnd_pt_dst = MEM_mallocN(sizeof(*rnd_pt_src), __func__);
+ memcpy(rnd_pt_dst, rnd_pt_src, sizeof(*rnd_pt_src));
+ return rnd_pt_dst;
+}
+
static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt)
{
struct ImageUI_Data *rnd_data = rnd_pt;
@@ -532,9 +539,10 @@ static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layo
}
/* 5 layer button callbacks... */
-static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v)
+static void image_multi_cb(bContext *C, void *rnd_pt, void *rr_v)
{
- ImageUser *iuser = iuser_v;
+ struct ImageUI_Data *rnd_data = rnd_pt;
+ ImageUser *iuser = rnd_data->iuser;
BKE_image_multilayer_index(rr_v, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
@@ -575,6 +583,8 @@ static bool ui_imageuser_layer_menu_step(bContext *C, int direction, void *rnd_p
BLI_assert(0);
}
+ BKE_image_release_renderresult(scene, image);
+
if (changed) {
BKE_image_multilayer_index(rr, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
@@ -662,10 +672,11 @@ static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt
}
/* 5 view button callbacks... */
-static void image_multiview_cb(bContext *C, void *ima_v, void *iuser_v)
+static void image_multiview_cb(bContext *C, void *rnd_pt, void *UNUSED(arg_v))
{
- Image *ima = ima_v;
- ImageUser *iuser = iuser_v;
+ struct ImageUI_Data *rnd_data = rnd_pt;
+ Image *ima = rnd_data->image;
+ ImageUser *iuser = rnd_data->iuser;
BKE_image_multiview_index(ima, iuser);
WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
@@ -692,7 +703,7 @@ static void uiblock_layer_pass_buttons(
uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w,
short *render_slot)
{
- static struct ImageUI_Data rnd_pt; /* XXX, workaround */
+ struct ImageUI_Data rnd_pt_local, *rnd_pt = NULL;
uiBlock *block = uiLayoutGetBlock(layout);
uiBut *but;
RenderLayer *rl = NULL;
@@ -708,10 +719,10 @@ static void uiblock_layer_pass_buttons(
wmenu2 = (3 * w) / 5;
wmenu3 = (3 * w) / 6;
wmenu4 = (3 * w) / 6;
-
- rnd_pt.image = image;
- rnd_pt.iuser = iuser;
- rnd_pt.rpass_index = 0;
+
+ rnd_pt_local.image = image;
+ rnd_pt_local.iuser = iuser;
+ rnd_pt_local.rpass_index = 0;
/* menu buts */
if (render_slot) {
@@ -723,10 +734,12 @@ static void uiblock_layer_pass_buttons(
BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1);
}
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
but = uiDefMenuBut(block, ui_imageuser_slot_menu, image, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot"));
UI_but_func_menu_step_set(but, ui_imageuser_slot_menu_step);
- UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
}
if (rr) {
@@ -738,15 +751,18 @@ static void uiblock_layer_pass_buttons(
fake_name = ui_imageuser_layer_fake_name(rr);
rpass_index = iuser->layer - (fake_name ? 1 : 0);
rl = BLI_findlink(&rr->layers, rpass_index);
- rnd_pt.rpass_index = rpass_index;
+ rnd_pt_local.rpass_index = rpass_index;
if (RE_layers_have_name(rr)) {
display_name = rl ? rl->name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_layer_menu, &rnd_pt, display_name,
- 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
+ but = uiDefMenuBut(
+ block, ui_imageuser_layer_menu, rnd_pt, display_name,
+ 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer"));
UI_but_func_menu_step_set(but, ui_imageuser_layer_menu_step);
- UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
}
/* pass */
@@ -754,11 +770,14 @@ static void uiblock_layer_pass_buttons(
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL);
display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : "");
- but = uiDefMenuBut(block, ui_imageuser_pass_menu, &rnd_pt, IFACE_(display_name),
- 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
+ but = uiDefMenuBut(
+ block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name),
+ 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass"));
UI_but_func_menu_step_set(but, ui_imageuser_pass_menu_step);
- UI_but_func_set(but, image_multi_cb, rr, iuser);
+ UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
/* view */
if (BLI_listbase_count_ex(&rr->views, 2) > 1 &&
@@ -767,9 +786,13 @@ static void uiblock_layer_pass_buttons(
rview = BLI_findlink(&rr->views, iuser->view);
display_name = rview ? rview->name : "";
- but = uiDefMenuBut(block, ui_imageuser_view_menu_rr, &rnd_pt, display_name, 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View"));
- UI_but_func_set(but, image_multi_cb, rr, iuser);
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
+ but = uiDefMenuBut(
+ block, ui_imageuser_view_menu_rr, rnd_pt, display_name,
+ 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View"));
+ UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
}
}
@@ -787,9 +810,13 @@ static void uiblock_layer_pass_buttons(
}
}
- but = uiDefMenuBut(block, ui_imageuser_view_menu_multiview, &rnd_pt, display_name, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View"));
- UI_but_func_set(but, image_multiview_cb, image, iuser);
+ rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
+ but = uiDefMenuBut(
+ block, ui_imageuser_view_menu_multiview, rnd_pt, display_name,
+ 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View"));
+ UI_but_funcN_set(but, image_multiview_cb, rnd_pt, NULL);
UI_but_type_set_menu_from_pulldown(but);
+ rnd_pt = NULL;
}
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 06caf930988..1158e692182 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1061,6 +1061,12 @@ typedef struct ImageOpenData {
ImageFormatData im_format;
} ImageOpenData;
+typedef struct ImageFrameRange {
+ struct ImageFrameRange *next, *prev;
+ ListBase frames;
+ char filepath[FILE_MAX];
+} ImageFrameRange;
+
typedef struct ImageFrame {
struct ImageFrame *next, *prev;
int framenr;
@@ -1086,10 +1092,10 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
* \param frames [out] the list of frame numbers found in the files matching the first one by name
* \param path [out] the full path of the first file in the list of image files
*/
-static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen)
+static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all)
{
char dir[FILE_MAXDIR];
- bool is_first_entry = true;
+ ImageFrameRange *frame_range = NULL;
RNA_string_get(ptr, "directory", dir);
RNA_BEGIN (ptr, itemptr, "files")
@@ -1101,29 +1107,26 @@ static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *p
ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
/* use the first file in the list as base filename */
- if (is_first_entry) {
- BLI_join_dirfile(path, maxlen, dir, filename);
- frame->framenr = BLI_stringdec(filename, base_head, base_tail, &digits);
- BLI_addtail(frames, frame);
- is_first_entry = false;
+ frame->framenr = BLI_stringdec(filename, head, tail, &digits);
+
+ /* still in the same sequence */
+ if ((frame_range != NULL) &&
+ (STREQLEN(base_head, head, FILE_MAX)) &&
+ (STREQLEN(base_tail, tail, FILE_MAX)))
+ {
+ /* pass */
}
else {
- frame->framenr = BLI_stringdec(filename, head, tail, &digits);
+ /* start a new frame range */
+ frame_range = MEM_callocN(sizeof(*frame_range), __func__);
+ BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename);
+ BLI_addtail(frames_all, frame_range);
- /* still in the same sequence */
- if ((STREQLEN(base_head, head, FILE_MAX)) &&
- (STREQLEN(base_tail, tail, FILE_MAX)))
- {
- BLI_addtail(frames, frame);
- }
- else {
- /* different file base name found, is ignored */
- MEM_freeN(filename);
- MEM_freeN(frame);
- break;
- }
+ BLI_strncpy(base_head, head, sizeof(base_head));
+ BLI_strncpy(base_tail, tail, sizeof(base_tail));
}
+ BLI_addtail(&frame_range->frames, frame);
MEM_freeN(filename);
}
RNA_END
@@ -1164,6 +1167,52 @@ static int image_sequence_get_len(ListBase *frames, int *ofs)
return 0;
}
+static Image *image_open_single(
+ wmOperator *op, const char *filepath, const char *relbase,
+ bool is_relative_path, bool use_multiview, int frame_seq_len)
+{
+ bool exists = false;
+ Image *ima = NULL;
+
+ errno = 0;
+ ima = BKE_image_load_exists_ex(filepath, &exists);
+
+ if (!ima) {
+ if (op->customdata) MEM_freeN(op->customdata);
+ BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
+ filepath, errno ? strerror(errno) : TIP_("unsupported image format"));
+ return NULL;
+ }
+
+ if (!exists) {
+ /* only image path after save, never ibuf */
+ if (is_relative_path) {
+ BLI_path_rel(ima->name, relbase);
+ }
+
+ /* handle multiview images */
+ if (use_multiview) {
+ ImageOpenData *iod = op->customdata;
+ ImageFormatData *imf = &iod->im_format;
+
+ ima->flag |= IMA_USE_VIEWS;
+ ima->views_format = imf->views_format;
+ *ima->stereo3d_format = imf->stereo3d_format;
+ }
+ else {
+ ima->flag &= ~IMA_USE_VIEWS;
+ BKE_image_free_views(ima);
+ }
+
+ if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) {
+ ima->source = IMA_SRC_SEQUENCE;
+ }
+ }
+
+ return ima;
+}
+
+
static int image_open_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -1174,70 +1223,60 @@ static int image_open_exec(bContext *C, wmOperator *op)
ImageOpenData *iod = op->customdata;
PointerRNA idptr;
Image *ima = NULL;
- char path[FILE_MAX];
+ char filepath[FILE_MAX];
int frame_seq_len = 0;
int frame_ofs = 1;
- bool exists = false;
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
+ const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview");
- RNA_string_get(op->ptr, "filepath", path);
+ if (!op->customdata)
+ image_open_init(C, op);
+
+ RNA_string_get(op->ptr, "filepath", filepath);
if (RNA_struct_property_is_set(op->ptr, "directory") &&
RNA_struct_property_is_set(op->ptr, "files"))
{
- /* only to pass to imbuf */
- char path_full[FILE_MAX];
- BLI_strncpy(path_full, path, sizeof(path_full));
- BLI_path_abs(path_full, G.main->name);
+ bool was_relative = BLI_path_is_rel(filepath);
+ ListBase frame_ranges_all;
- if (!IMB_isanim(path_full)) {
- bool was_relative = BLI_path_is_rel(path);
- ListBase frames;
+ BLI_listbase_clear(&frame_ranges_all);
+ image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all);
+ for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range; frame_range = frame_range->next) {
+ int frame_range_ofs;
+ int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs);
+ BLI_freelistN(&frame_range->frames);
- BLI_listbase_clear(&frames);
- image_sequence_get_frames(op->ptr, &frames, path, sizeof(path));
- frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
- BLI_freelistN(&frames);
+ char filepath_range[FILE_MAX];
+ BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range));
if (was_relative) {
- BLI_path_rel(path, G.main->name);
+ BLI_path_rel(filepath_range, bmain->name);
}
- }
- }
-
- errno = 0;
- ima = BKE_image_load_exists_ex(path, &exists);
+ Image *ima_range = image_open_single(
+ op, filepath_range, bmain->name,
+ is_relative_path, use_multiview, frame_range_seq_len);
- if (!ima) {
- if (op->customdata) MEM_freeN(op->customdata);
- BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s",
- path, errno ? strerror(errno) : TIP_("unsupported image format"));
- return OPERATOR_CANCELLED;
- }
-
- if (!op->customdata)
- image_open_init(C, op);
-
- /* handle multiview images */
- if (RNA_boolean_get(op->ptr, "use_multiview")) {
- ImageFormatData *imf = &iod->im_format;
-
- ima->flag |= IMA_USE_VIEWS;
- ima->views_format = imf->views_format;
- *ima->stereo3d_format = imf->stereo3d_format;
+ /* take the first image */
+ if ((ima == NULL) && ima_range) {
+ ima = ima_range;
+ frame_seq_len = frame_range_seq_len;
+ frame_ofs = frame_range_ofs;
+ }
+ }
+ BLI_freelistN(&frame_ranges_all);
}
else {
- ima->flag &= ~IMA_USE_VIEWS;
- BKE_image_free_views(ima);
+ /* for drag & drop etc. */
+ ima = image_open_single(
+ op, filepath, bmain->name,
+ is_relative_path, use_multiview, 1);
}
- /* only image path after save, never ibuf */
- if (is_relative_path) {
- if (!exists) {
- BLI_path_rel(ima->name, bmain->name);
- }
+ if (ima == NULL) {
+ return OPERATOR_CANCELLED;
}
/* hook into UI */
@@ -1245,11 +1284,9 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iod->pprop.prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&ima->id);
- if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) {
- ima->source = IMA_SRC_SEQUENCE;
- }
+
RNA_id_pointer_create(&ima->id, &idptr);
RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr);
RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop);
@@ -2359,7 +2396,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
if (prop) {
/* when creating new ID blocks, use is already 1, but RNA
- * pointer se also increases user, so this compensates it */
+ * pointer use also increases user, so this compensates it */
id_us_min(&ima->id);
RNA_id_pointer_create(&ima->id, &idptr);
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index d7249897723..ea3869ef387 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -1726,7 +1726,7 @@ static int node_insert_offset_modal(bContext *C, wmOperator *UNUSED(op), const w
float duration;
bool redraw = false;
- if (!snode || event->type != TIMER || iofsd->anim_timer != event->customdata)
+ if (!snode || event->type != TIMER || iofsd == NULL || iofsd->anim_timer != event->customdata)
return OPERATOR_PASS_THROUGH;
duration = (float)iofsd->anim_timer->duration;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 5173b18dc9b..b357e742d78 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1568,7 +1568,7 @@ static void outliner_draw_tree_element(
else
offsx += 2 * ufac;
- if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) {
+ if (tselem->type == 0 && ID_IS_LINKED(tselem->id)) {
glPixelTransferf(GL_ALPHA_SCALE, 0.5f);
if (tselem->id->tag & LIB_TAG_MISSING) {
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN);
@@ -1579,8 +1579,6 @@ static void outliner_draw_tree_element(
else {
UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT);
}
- /* TODO use proper icons or other UI feedback, for sake of simplicity for now using basic
- * color code to show assets and their state. */
if (tselem->id->uuid) {
offsx += UI_UNIT_X;
UI_icon_draw((float)startx + offsx - 0.5f * ufac, (float)*starty + 1.5f * ufac, ICON_SOLO_ON);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index b0cd3aabbfd..3c47f542dae 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -417,9 +417,9 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
+ if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) {
BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')",
- old_id->name, new_id->name);
+ old_id ? old_id->name : "Invalid ID", new_id ? new_id->name : "Invalid ID");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index f3235d07757..a840a720b3d 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -435,11 +435,12 @@ static void id_local_cb(
bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te),
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data))
{
- if (ID_IS_LINKED_DATABLOCK(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
+ if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
Main *bmain = CTX_data_main(C);
/* if the ID type has no special local function,
- * just clear the lib */
- if (id_make_local(bmain, tselem->id, false) == false) {
+ * just clear the lib. */
+ /* XXX This is very, very, **very** suspicious - should not be handled that way at all!!! */
+ if (id_make_local(bmain, tselem->id, false, false) == false) {
id_clear_lib_data(bmain, tselem->id);
}
}
@@ -516,23 +517,16 @@ static void group_linkobs2scene_cb(
Group *group = (Group *)tselem->id;
GroupObject *gob;
Base *base;
-
+
for (gob = group->gobject.first; gob; gob = gob->next) {
base = BKE_scene_base_find(scene, gob->ob);
- if (base) {
- base->object->flag |= SELECT;
- base->flag |= SELECT;
- }
- else {
+ if (!base) {
/* link to scene */
- base = MEM_callocN(sizeof(Base), "add_base");
- BLI_addhead(&scene->base, base);
- base->lay = gob->ob->lay;
- gob->ob->flag |= SELECT;
- base->flag = gob->ob->flag;
- base->object = gob->ob;
+ base = BKE_scene_base_add(scene, gob->ob);
id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */
}
+ base->object->flag |= SELECT;
+ base->flag |= SELECT;
}
}
@@ -1352,7 +1346,7 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
- eOutlinerIdOpTypes event;
+ eOutlinerLibOpTypes event;
/* check for invalid states */
if (soops == NULL)
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index c11a4d2e5a3..ede6b7ce469 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -1071,7 +1071,7 @@ static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, const
{
bool is_type_set = RNA_struct_property_is_set(op->ptr, "type");
int type = -1;
- int prop_flag = SEQPROP_ENDFRAME;
+ int prop_flag = SEQPROP_ENDFRAME | SEQPROP_NOPATHS;
if (is_type_set) {
type = RNA_enum_get(op->ptr, "type");
@@ -1106,9 +1106,6 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_filesel(
- ot, 0, FILE_SPECIAL, FILE_OPENFILE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME);
RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_TYPE_CROSS, "Type", "Sequencer effect type");
RNA_def_float_vector(ot->srna, "color", 3, NULL, 0.0f, 1.0f, "Color",
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 791ece14cb9..f5289a0d245 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -237,7 +237,9 @@ static struct TextureDrawState {
bool texpaint_material; /* use material slots for texture painting */
} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, false, {0, 0, 0, 0}, false, false};
-static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material *ma, struct TextureDrawState gtexdraw)
+static bool set_draw_settings_cached(
+ int clearcache, MTexPoly *texface, Material *ma,
+ const struct TextureDrawState *gtexdraw)
{
static Material *c_ma;
static int c_textured;
@@ -253,7 +255,7 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
int lit = 0;
int has_texface = texface != NULL;
bool need_set_tpage = false;
- bool texpaint = ((gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) != 0);
+ bool texpaint = ((gtexdraw->ob->mode & OB_MODE_TEXTURE_PAINT) != 0);
Image *ima = NULL;
@@ -271,16 +273,18 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
c_ma = NULL;
}
else {
- textured = gtexdraw.is_tex;
+ textured = gtexdraw->is_tex;
}
/* convert number of lights into boolean */
- if (gtexdraw.is_lit) lit = 1;
+ if (gtexdraw->is_lit) {
+ lit = 1;
+ }
- backculled = gtexdraw.use_backface_culling;
+ backculled = gtexdraw->use_backface_culling;
if (ma) {
if (ma->mode & MA_SHLESS) lit = 0;
- if (gtexdraw.use_game_mat) {
+ if (gtexdraw->use_game_mat) {
backculled = backculled || (ma->game.flag & GEMAT_BACKCULL);
alphablend = ma->game.alpha_blend;
}
@@ -294,10 +298,10 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
alphablend = GPU_BLEND_ALPHA;
}
else if (texpaint) {
- if (gtexdraw.texpaint_material)
+ if (gtexdraw->texpaint_material)
ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
else
- ima = gtexdraw.canvas;
+ ima = gtexdraw->canvas;
}
else
textured = 0;
@@ -375,7 +379,7 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material
if (c_textured && !c_badtex) {
options |= GPU_SHADER_TEXTURE_2D;
}
- if (gtexdraw.two_sided_lighting) {
+ if (gtexdraw->two_sided_lighting) {
options |= GPU_SHADER_TWO_SIDED;
}
@@ -495,7 +499,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
Gtexdraw.two_sided_lighting = (me->flag & ME_TWOSIDED);
memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
- set_draw_settings_cached(1, NULL, NULL, Gtexdraw);
+ set_draw_settings_cached(1, NULL, NULL, &Gtexdraw);
glCullFace(GL_BACK);
}
@@ -553,7 +557,7 @@ static DMDrawOption draw_tface__set_draw_legacy(MTexPoly *mtexpoly, const bool h
if (ma && (ma->game.flag & GEMAT_INVISIBLE))
return DM_DRAW_OPTION_SKIP;
- invalidtexture = set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw);
+ invalidtexture = set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw);
if (mtexpoly && invalidtexture) {
glColor3ub(0xFF, 0x00, 0xFF);
@@ -594,7 +598,7 @@ static DMDrawOption draw_tface__set_draw(MTexPoly *mtexpoly, const bool UNUSED(h
if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return DM_DRAW_OPTION_SKIP;
if (mtexpoly || Gtexdraw.is_texpaint)
- set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw);
+ set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw);
/* always use color from mcol, as set in update_tface_color_layer */
return DM_DRAW_OPTION_NORMAL;
@@ -664,7 +668,7 @@ static void update_tface_color_layer(DerivedMesh *dm, bool use_mcol)
copy_mode = COPY_PREV;
}
}
- else if (mtexpoly && set_draw_settings_cached(0, mtexpoly, ma, Gtexdraw)) {
+ else if (mtexpoly && set_draw_settings_cached(0, mtexpoly, ma, &Gtexdraw)) {
int loop_index = mp->loopstart;
for (j = 0; j < mp->totloop; j++, loop_index++) {
finalCol[loop_index].r = 255;
@@ -830,7 +834,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl)
}
}
else {
- badtex = set_draw_settings_cached(0, mtpoly, mat, Gtexdraw);
+ badtex = set_draw_settings_cached(0, mtpoly, mat, &Gtexdraw);
if (badtex) {
continue;
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 90f79f0ff69..b117a5e68d8 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -3079,7 +3079,9 @@ static int viewselected_exec(bContext *C, wmOperator *op)
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
ok = PE_minmax(scene, min, max);
}
- else if (ob && (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT))) {
+ else if (ob &&
+ (ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)))
+ {
BKE_paint_stroke_get_average(scene, ob, min);
copy_v3_v3(max, min);
ok = true;
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 6d831c667a8..bdd2702a6ce 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -274,6 +274,7 @@ bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]);
void VIEW3D_OT_snap_selected_to_grid(struct wmOperatorType *ot);
void VIEW3D_OT_snap_selected_to_cursor(struct wmOperatorType *ot);
+void VIEW3D_OT_snap_selected_to_active(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_grid(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 1c84ce3c985..b273f46fca3 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -214,6 +214,7 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_snap_selected_to_grid);
WM_operatortype_append(VIEW3D_OT_snap_selected_to_cursor);
+ WM_operatortype_append(VIEW3D_OT_snap_selected_to_active);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_grid);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_center);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index ac05853e6d0..7448d4c658e 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -312,25 +312,9 @@ static void view3d_win_to_ray_segment(
if (!r_ray_co) r_ray_co = _ray_co;
if (!r_ray_dir) r_ray_dir = _ray_dir;
+ ED_view3d_win_to_origin(ar, mval, r_ray_co);
ED_view3d_win_to_vector(ar, mval, r_ray_dir);
- if (rv3d->is_persp) {
- copy_v3_v3(r_ray_co, rv3d->viewinv[3]);
- }
- else {
- r_ray_co[0] = 2.0f * mval[0] / ar->winx - 1.0f;
- r_ray_co[1] = 2.0f * mval[1] / ar->winy - 1.0f;
-
- if (rv3d->persp == RV3D_CAMOB) {
- r_ray_co[2] = -1.0f;
- }
- else {
- r_ray_co[2] = 0.0f;
- }
-
- mul_project_m4_v3(rv3d->persinv, r_ray_co);
- }
-
if ((rv3d->is_persp == false) && (rv3d->persp != RV3D_CAMOB)) {
end_offset = v3d->far / 2.0f;
start_offset = -end_offset;
@@ -347,7 +331,7 @@ static void view3d_win_to_ray_segment(
}
}
-BLI_INLINE bool view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3])
+bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3])
{
if ((rv3d->rflag & RV3D_CLIPPING) &&
(clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6,
@@ -384,7 +368,7 @@ bool ED_view3d_win_to_ray_ex(
/* bounds clipping */
if (do_clip) {
- return view3d_clip_segment(ar->regiondata, r_ray_start, ray_end);
+ return ED_view3d_clip_segment(ar->regiondata, r_ray_start, ray_end);
}
return true;
@@ -549,6 +533,37 @@ void ED_view3d_win_to_delta(const ARegion *ar, const float mval[2], float out[3]
}
/**
+ * Calculate a 3d origin from 2d window coordinates.
+ * \note Orthographic views have a less obvious origin,
+ * Since far clip can be a very large value resulting in numeric precision issues,
+ * the origin in this case is close to zero coordinate.
+ *
+ * \param ar The region (used for the window width and height).
+ * \param mval The area relative 2d location (such as event->mval converted to floats).
+ * \param out The resulting normalized world-space direction vector.
+ */
+void ED_view3d_win_to_origin(const ARegion *ar, const float mval[2], float out[3])
+{
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->is_persp) {
+ copy_v3_v3(out, rv3d->viewinv[3]);
+ }
+ else {
+ out[0] = 2.0f * mval[0] / ar->winx - 1.0f;
+ out[1] = 2.0f * mval[1] / ar->winy - 1.0f;
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ out[2] = -1.0f;
+ }
+ else {
+ out[2] = 0.0f;
+ }
+
+ mul_project_m4_v3(rv3d->persinv, out);
+ }
+}
+
+/**
* Calculate a 3d direction vector from 2d window coordinates.
* This direction vector starts and the view in the direction of the 2d window coordinates.
* In orthographic view all window coordinates yield the same vector.
@@ -599,7 +614,7 @@ bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2
/* bounds clipping */
if (do_clip) {
- return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end);
+ return ED_view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end);
}
return true;
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index e8e7d3c62fb..5dd69cc66eb 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -44,6 +44,7 @@
#include "BKE_main.h"
#include "BKE_mball.h"
#include "BKE_object.h"
+#include "BKE_report.h"
#include "BKE_tracking.h"
#include "WM_api.h"
@@ -204,7 +205,7 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
/* *************************************************** */
-static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
+static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
@@ -213,15 +214,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
TransVertStore tvs = {NULL};
TransVert *tv;
float imat[3][3], bmat[3][3];
- const float *cursor_global;
float center_global[3];
float offset_global[3];
int a;
- const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
-
- cursor_global = ED_view3d_cursor3d_get(scene, v3d);
-
if (use_offset) {
if ((v3d && v3d->around == V3D_AROUND_ACTIVE) &&
snap_calc_active_center(C, true, center_global))
@@ -231,11 +227,11 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
else {
snap_curs_to_sel_ex(C, center_global);
}
- sub_v3_v3v3(offset_global, cursor_global, center_global);
+ sub_v3_v3v3(offset_global, snap_target_global, center_global);
}
if (obedit) {
- float cursor_local[3];
+ float snap_target_local[3];
if (ED_transverts_check_obedit(obedit))
ED_transverts_create_from_obedit(&tvs, obedit, 0);
@@ -246,8 +242,8 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
invert_m3_m3(imat, bmat);
/* get the cursor in object space */
- sub_v3_v3v3(cursor_local, cursor_global, obedit->obmat[3]);
- mul_m3_v3(imat, cursor_local);
+ sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]);
+ mul_m3_v3(imat, snap_target_local);
if (use_offset) {
float offset_local[3];
@@ -262,7 +258,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
else {
tv = tvs.transverts;
for (a = 0; a < tvs.transverts_tot; a++, tv++) {
- copy_v3_v3(tv->loc, cursor_local);
+ copy_v3_v3(tv->loc, snap_target_local);
}
}
@@ -274,10 +270,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
bPoseChannel *pchan;
bArmature *arm = obact->data;
- float cursor_local[3];
+ float snap_target_local[3];
invert_m4_m4(obact->imat, obact->obmat);
- mul_v3_m4v3(cursor_local, obact->imat, cursor_global);
+ mul_v3_m4v3(snap_target_local, obact->imat, snap_target_global);
for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
if ((pchan->bone->flag & BONE_SELECTED) &&
@@ -311,7 +307,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose);
}
else {
- BKE_armature_loc_pose_to_bone(pchan, cursor_local, cursor_pose);
+ BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose);
}
/* copy new position */
@@ -367,7 +363,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global);
}
else {
- copy_v3_v3(cursor_parent, cursor_global);
+ copy_v3_v3(cursor_parent, snap_target_global);
}
sub_v3_v3(cursor_parent, ob->obmat[3]);
@@ -401,6 +397,18 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
+{
+ const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
+
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ const float *snap_target_global = ED_view3d_cursor3d_get(scene, v3d);
+
+ return snap_selected_to_location(C, snap_target_global, use_offset);
+}
+
void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
{
/* identifiers */
@@ -409,7 +417,7 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
ot->idname = "VIEW3D_OT_snap_selected_to_cursor";
/* api callbacks */
- ot->exec = snap_sel_to_curs_exec;
+ ot->exec = snap_selected_to_cursor_exec;
ot->poll = ED_operator_view3d_active;
/* flags */
@@ -419,6 +427,34 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", "");
}
+static int snap_selected_to_active_exec(bContext *C, wmOperator *op)
+{
+ float snap_target_global[3];
+
+ if (snap_calc_active_center(C, false, snap_target_global) == false) {
+ BKE_report(op->reports, RPT_ERROR, "No active element found!");
+ return OPERATOR_CANCELLED;
+ }
+
+ return snap_selected_to_location(C, snap_target_global, false);
+}
+
+void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Snap Selection to Active";
+ ot->description = "Snap selected item(s) to the active item";
+ ot->idname = "VIEW3D_OT_snap_selected_to_active";
+
+ /* api callbacks */
+ ot->exec = snap_selected_to_active_exec;
+ ot->poll = ED_operator_view3d_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
/* *************************************************** */
static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index fc32613c1ab..b7456facbdf 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -5273,13 +5273,9 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
skip_invert = true;
if (skip_invert == false && constinv == false) {
- if (constinv == false)
- ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
-
+ ob->transflag |= OB_NO_CONSTRAINTS; /* BKE_object_where_is_calc_time checks this */
BKE_object_where_is_calc(t->scene, ob);
-
- if (constinv == false)
- ob->transflag &= ~OB_NO_CONSTRAINTS;
+ ob->transflag &= ~OB_NO_CONSTRAINTS;
}
else
BKE_object_where_is_calc(t->scene, ob);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 59dfe18139a..1d4872cca7a 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -110,6 +110,12 @@ struct SnapObjectContext {
};
+enum eViewProj {
+ VIEW_PROJ_NONE = -1,
+ VIEW_PROJ_ORTHO = 0,
+ VIEW_PROJ_PERSP = -1,
+};
+
static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt);
@@ -137,10 +143,6 @@ struct RayCastAll_Data {
Object *ob;
unsigned int ob_uuid;
- /* DerivedMesh only */
- DerivedMesh *dm;
- const struct MLoopTri *dm_looptri;
-
/* output data */
ListBase *hit_list;
bool retval;
@@ -218,76 +220,177 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
/* -------------------------------------------------------------------- */
-/** \name Internal Object Snapping API
+/** \Common utilities
* \{ */
+
+/**
+ * Struct that kepts basic information about a BVHTree build from a editmesh.
+ */
+typedef struct BVHTreeFromMeshType {
+ void *userdata;
+ char type;
+} BVHTreeFromMeshType;
+
+typedef struct PreDefProject {
+ float pmat[4][4]; /* perspective matrix multiplied by object matrix */
+ float win_half[2];
+ float dist_px_sq;
+} PreDefProject;
+
+static void precalc_project(
+ PreDefProject *projectdefs, const ARegion *ar,
+ const float dist_px, float obmat[4][4])
+{
+ float (*pmat)[4] = ((RegionView3D *)ar->regiondata)->persmat;
+ if (obmat) {
+ mul_m4_m4m4(projectdefs->pmat, pmat, obmat);
+ }
+ else {
+ copy_m4_m4(projectdefs->pmat, pmat);
+ }
+ projectdefs->win_half[0] = ar->winx / 2;
+ projectdefs->win_half[1] = ar->winy / 2;
+ projectdefs->dist_px_sq = SQUARE(dist_px);
+}
+
+/**
+ * From a threshold (maximum distance to snap in pixels) returns:
+ *
+ * - The *real* distance (3D) if you are in orthographic-view.
+ * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view.
+ */
+static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px)
+{
+ const RegionView3D *rv3d = ar->regiondata;
+ if (ar->winx >= ar->winy)
+ return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0];
+ else
+ return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1];
+}
+
+static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int index)
+{
+ switch (meshdata->type) {
+ case SNAP_MESH:
+ {
+ BVHTreeFromMesh *data = meshdata->userdata;
+ const MVert *vert = data->vert;
+ return vert[index].co;
+ }
+ case SNAP_EDIT_MESH:
+ {
+ BVHTreeFromEditMesh *data = meshdata->userdata;
+ BMVert *eve = BM_vert_at_index(data->em->bm, index);
+ return eve->co;
+ }
+ }
+ return NULL;
+}
+
+static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3])
+{
+ switch (meshdata->type) {
+ case SNAP_MESH:
+ {
+ BVHTreeFromMesh *data = meshdata->userdata;
+ const MVert *vert = data->vert;
+ normal_short_to_float_v3(r_no, vert->no);
+ break;
+ }
+ case SNAP_EDIT_MESH:
+ {
+ BVHTreeFromEditMesh *data = meshdata->userdata;
+ BMVert *eve = BM_vert_at_index(data->em->bm, index);
+ copy_v3_v3(r_no, eve->no);
+ break;
+ }
+ }
+}
+
+static void get_edge_verts(
+ const BVHTreeFromMeshType *meshdata, const int index,
+ const float *v_pair[2])
+{
+ switch (meshdata->type) {
+ case SNAP_MESH:
+ {
+ BVHTreeFromMesh *data = meshdata->userdata;
+
+ const MVert *vert = data->vert;
+ const MEdge *edge = data->edge + index;
+
+ v_pair[0] = vert[edge->v1].co;
+ v_pair[1] = vert[edge->v2].co;
+ break;
+ }
+ case SNAP_EDIT_MESH:
+ {
+ BVHTreeFromEditMesh *data = meshdata->userdata;
+ BMEdge *eed = BM_edge_at_index(data->em->bm, index);
+
+ v_pair[0] = eed->v1->co;
+ v_pair[1] = eed->v2->co;
+ break;
+ }
+ }
+}
+
#define V3_MUL_ELEM(a, b) \
(a)[0] * (b)[0], \
(a)[1] * (b)[1], \
(a)[2] * (b)[2]
-static bool test_vert(
- const float vco[3], const float vno[3], const float ray_co[3], const float ray_dir[3],
- const float ray_depth_range[2], const float scale[3], const bool is_persp,
+static bool test_vert_dist(
+ const float vco[3], const float ray_co[3], const float ray_dir[3],
+ const float ray_depth_range[2], const float scale[3],
/* read/write args */
float *ray_depth, float *dist_to_ray_sq,
/* return args */
- float r_co[3], float r_no[3])
+ float r_co[3])
{
const float vco_sc[3] = {V3_MUL_ELEM(vco, scale)};
- const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
+ const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
- float depth;
- float dist_sq = dist_squared_to_ray_v3(co_sc, dir_sc, vco_sc, &depth);
+ float depth, dist_sq;
+ dist_sq = dist_squared_to_ray_v3(origin_sc, dir_sc, vco_sc, &depth);
if (depth < ray_depth_range[0]) {
return false;
}
- if (is_persp) {
- dist_sq /= SQUARE(depth);
- }
-
if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
*dist_to_ray_sq = dist_sq;
copy_v3_v3(r_co, vco);
- if (vno) {
- copy_v3_v3(r_no, vno);
- }
-
*ray_depth = depth;
return true;
}
return false;
}
-static bool test_edge(
+static bool test_edge_dist(
const float v1[3], const float v2[3], const float ray_co[3], const float ray_dir[3],
- const float ray_depth_range[2], const float scale[3], const bool is_persp,
+ const float ray_depth_range[2], const float scale[3],
/* read/write args */
float *ray_depth, float *dist_to_ray_sq,
/* return args */
- float r_co[3], float r_no[3])
+ float r_co[3])
{
const float v1_sc[3] = {V3_MUL_ELEM(v1, scale)};
const float v2_sc[3] = {V3_MUL_ELEM(v2, scale)};
const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)};
const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)};
- float tmp_co[3], depth;
- float dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth);
+ float tmp_co[3], depth, dist_sq;
+ dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth);
if (depth < ray_depth_range[0]) {
return false;
}
- if (is_persp) {
- dist_sq /= SQUARE(depth);
- }
-
if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
*dist_to_ray_sq = dist_sq;
@@ -297,10 +400,6 @@ static bool test_edge(
copy_v3_v3(r_co, tmp_co);
- if (r_no) {
- sub_v3_v3v3(r_no, v1, v2);
- }
-
*ray_depth = depth;
return true;
}
@@ -309,50 +408,369 @@ static bool test_edge(
#undef V3_MUL_ELEM
+static bool test_projected_vert_dist(
+ PreDefProject *projectdefs,
+ const float co[3], const enum eViewProj view_proj,
+ const float mval[2], const float depth_range[2],
+ float r_co[3])
+{
+ float depth;
+ float(*pmat)[4] = projectdefs->pmat;
+ if (view_proj == VIEW_PROJ_PERSP) {
+ depth = mul_project_m4_v3_zfac(pmat, co);
+ if (depth < depth_range[0] || depth > depth_range[1]) {
+ return false;
+ }
+ }
+
+ float co2d[2] = {
+ (dot_m4_v3_row_x(pmat, co) + pmat[3][0]),
+ (dot_m4_v3_row_y(pmat, co) + pmat[3][1]),
+ };
+
+ if (view_proj == VIEW_PROJ_PERSP) {
+ mul_v2_fl(co2d, 1 / depth);
+ }
+
+ co2d[0] += 1.0f;
+ co2d[1] += 1.0f;
+ co2d[0] *= projectdefs->win_half[0];
+ co2d[1] *= projectdefs->win_half[1];
+
+ const float dist_sq = len_squared_v2v2(mval, co2d);
+ if (dist_sq < projectdefs->dist_px_sq) {
+ copy_v3_v3(r_co, co);
+ projectdefs->dist_px_sq = dist_sq;
+ return true;
+ }
+ return false;
+}
+
+static bool test_projected_edge_dist(
+ PreDefProject *projectdefs,
+ const float va[3], const float vb[3], const float ray_start[3], const float ray_normal[3],
+ const enum eViewProj view_proj, const float mval[2], const float depth_range[2],
+ float r_co[3])
+{
+
+ float tmp_co[3], depth;
+ dist_squared_ray_to_seg_v3(ray_start, ray_normal, va, vb, tmp_co, &depth);
+ return test_projected_vert_dist(projectdefs, tmp_co, view_proj, mval, depth_range, r_co);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+
+/** \Walk DFS
+ * \{ */
+typedef struct Object_Nearest2dPrecalc {
+ float ray_origin_local[3];
+ float ray_direction_local[3];
+ float ray_inv_dir[3];
+
+ PreDefProject projectdefs;
+ float mval[2];
+ bool sign[3];
+ bool r_axis_closest[3];
+ float depth_range[2];
+
+ void *userdata;
+ int index;
+ float co[3];
+ float no[3];
+} Object_Nearest2dPrecalc;
+
+
+static void nearest2d_precalc(
+ Object_Nearest2dPrecalc *neasrest_precalc, const ARegion *ar,
+ const float dist_px, float obmat[4][4],
+ const float ray_origin_local[3], const float ray_direction_local[3],
+ const float mval[2], const float depth_range[2])
+{
+ precalc_project(&neasrest_precalc->projectdefs, ar, dist_px, obmat);
+ copy_v3_v3(neasrest_precalc->ray_origin_local, ray_origin_local);
+ copy_v3_v3(neasrest_precalc->ray_direction_local, ray_direction_local);
+ copy_v2_v2(neasrest_precalc->mval, mval);
+ copy_v2_v2(neasrest_precalc->depth_range, depth_range);
+
+ for (int i = 0; i < 3; i++) {
+ neasrest_precalc->ray_inv_dir[i] =
+ (neasrest_precalc->ray_direction_local[i] != 0.0f) ?
+ (1.0f / neasrest_precalc->ray_direction_local[i]) : FLT_MAX;
+ neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f);
+ neasrest_precalc->r_axis_closest[i] = true;
+ }
+}
+
+static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data)
+{
+ Object_Nearest2dPrecalc *data = user_data;
+ float local_bvmin[3], local_bvmax[3];
+ if (data->sign[0]) {
+ local_bvmin[0] = bounds[0].max;
+ local_bvmax[0] = bounds[0].min;
+ }
+ else {
+ local_bvmin[0] = bounds[0].min;
+ local_bvmax[0] = bounds[0].max;
+ }
+ if (data->sign[1]) {
+ local_bvmin[1] = bounds[1].max;
+ local_bvmax[1] = bounds[1].min;
+ }
+ else {
+ local_bvmin[1] = bounds[1].min;
+ local_bvmax[1] = bounds[1].max;
+ }
+ if (data->sign[2]) {
+ local_bvmin[2] = bounds[2].max;
+ local_bvmax[2] = bounds[2].min;
+ }
+ else {
+ local_bvmin[2] = bounds[2].min;
+ local_bvmax[2] = bounds[2].max;
+ }
+
+ const float tmin[3] = {
+ (local_bvmin[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0],
+ (local_bvmin[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1],
+ (local_bvmin[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2],
+ };
+ const float tmax[3] = {
+ (local_bvmax[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0],
+ (local_bvmax[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1],
+ (local_bvmax[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2],
+ };
+ float va[3], vb[3];
+ float rtmin, rtmax;
+ int main_axis;
+
+ if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) {
+ rtmax = tmax[0];
+ va[0] = vb[0] = local_bvmax[0];
+ main_axis = 3;
+ data->r_axis_closest[0] = data->sign[0];
+ }
+ else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) {
+ rtmax = tmax[1];
+ va[1] = vb[1] = local_bvmax[1];
+ main_axis = 2;
+ data->r_axis_closest[1] = data->sign[1];
+ }
+ else {
+ rtmax = tmax[2];
+ va[2] = vb[2] = local_bvmax[2];
+ main_axis = 1;
+ data->r_axis_closest[2] = data->sign[2];
+ }
+
+ if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) {
+ rtmin = tmin[0];
+ va[0] = vb[0] = local_bvmin[0];
+ main_axis -= 3;
+ data->r_axis_closest[0] = !data->sign[0];
+ }
+ else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) {
+ rtmin = tmin[1];
+ va[1] = vb[1] = local_bvmin[1];
+ main_axis -= 1;
+ data->r_axis_closest[1] = !data->sign[1];
+ }
+ else {
+ rtmin = tmin[2];
+ va[2] = vb[2] = local_bvmin[2];
+ main_axis -= 2;
+ data->r_axis_closest[2] = !data->sign[2];
+ }
+ if (main_axis < 0) {
+ main_axis += 3;
+ }
+
+ /* if rtmin < rtmax, ray intersect `AABB` */
+ if (rtmin <= rtmax) {
+#ifdef IGNORE_BEHIND_RAY
+ /* `if rtmax < depth_min`, the whole `AABB` is behind us */
+ if (rtmax < min_depth) {
+ return fallback;
+ }
+#endif
+ const float proj = rtmin * data->ray_direction_local[main_axis];
+ data->r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj);
+ return true;
+ }
+#ifdef IGNORE_BEHIND_RAY
+ /* `if rtmin < depth_min`, the whole `AABB` is behing us */
+ else if (rtmin < min_depth) {
+ return fallback;
+ }
+#endif
+ if (data->sign[main_axis]) {
+ va[main_axis] = local_bvmax[main_axis];
+ vb[main_axis] = local_bvmin[main_axis];
+ }
+ else {
+ va[main_axis] = local_bvmin[main_axis];
+ vb[main_axis] = local_bvmax[main_axis];
+ }
+ float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]);
+
+ float (*pmat)[4] = data->projectdefs.pmat;
+ float depth_a = mul_project_m4_v3_zfac(pmat, va);
+ float depth_b = depth_a + pmat[main_axis][3] * scale;
+
+ float va2d[2] = {
+ (dot_m4_v3_row_x(pmat, va) + pmat[3][0]),
+ (dot_m4_v3_row_y(pmat, va) + pmat[3][1]),
+ };
+ float vb2d[2] = {
+ (va2d[0] + pmat[main_axis][0] * scale) / depth_b,
+ (va2d[1] + pmat[main_axis][1] * scale) / depth_b,
+ };
+
+ va2d[0] /= depth_a;
+ va2d[1] /= depth_a;
+
+ va2d[0] += 1.0f;
+ va2d[1] += 1.0f;
+ vb2d[0] += 1.0f;
+ vb2d[1] += 1.0f;
+
+ va2d[0] *= data->projectdefs.win_half[0];
+ va2d[1] *= data->projectdefs.win_half[1];
+ vb2d[0] *= data->projectdefs.win_half[0];
+ vb2d[1] *= data->projectdefs.win_half[1];
+
+ //float dvec[2], edge[2], rdist;
+ //sub_v2_v2v2(dvec, data->mval, va2d);
+ //sub_v2_v2v2(edge, vb2d, va2d);
+ float rdist;
+ short dvec[2] = {data->mval[0] - va2d[0], data->mval[1] - va2d[1]};
+ short edge[2] = {vb2d[0] - va2d[0], vb2d[1] - va2d[1]};
+ float lambda = dvec[0] * edge[0] + dvec[1] * edge[1];
+ if (lambda != 0.0f) {
+ lambda /= edge[0] * edge[0] + edge[1] * edge[1];
+ if (lambda <= 0.0f) {
+ rdist = len_squared_v2v2(data->mval, va2d);
+ data->r_axis_closest[main_axis] = true;
+ }
+ else if (lambda >= 1.0f) {
+ rdist = len_squared_v2v2(data->mval, vb2d);
+ data->r_axis_closest[main_axis] = false;
+ }
+ else {
+ va2d[0] += edge[0] * lambda;
+ va2d[1] += edge[1] * lambda;
+ rdist = len_squared_v2v2(data->mval, va2d);
+ data->r_axis_closest[main_axis] = lambda < 0.5f;
+ }
+ }
+ else {
+ rdist = len_squared_v2v2(data->mval, va2d);
+ }
+ return rdist < data->projectdefs.dist_px_sq;
+}
+
+static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata)
+{
+ struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+ const float co[3] = {
+ (bounds[0].min + bounds[0].max) / 2,
+ (bounds[1].min + bounds[1].max) / 2,
+ (bounds[2].min + bounds[2].max) / 2,
+ };
+
+ /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP)
+ * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO),
+ * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/
+ if (test_projected_vert_dist(
+ &neasrest_precalc->projectdefs, co, VIEW_PROJ_PERSP,
+ neasrest_precalc->mval, neasrest_precalc->depth_range,
+ neasrest_precalc->co))
+ {
+ copy_vert_no(neasrest_precalc->userdata, index, neasrest_precalc->no);
+ neasrest_precalc->index = index;
+ }
+ return true;
+}
+
+static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata)
+{
+ struct Object_Nearest2dPrecalc *neasrest_precalc = userdata;
+
+ const float *v_pair[2];
+ get_edge_verts(neasrest_precalc->userdata, index, v_pair);
+
+ /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP)
+ * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO),
+ * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/
+ if (test_projected_edge_dist(
+ &neasrest_precalc->projectdefs, v_pair[0], v_pair[1],
+ neasrest_precalc->ray_origin_local, neasrest_precalc->ray_direction_local,
+ VIEW_PROJ_PERSP, neasrest_precalc->mval, neasrest_precalc->depth_range,
+ neasrest_precalc->co))
+ {
+ sub_v3_v3v3(neasrest_precalc->no, v_pair[0], v_pair[1]);
+ neasrest_precalc->index = index;
+ }
+ return true;
+}
+
+static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char axis, void *userdata)
+{
+ const bool *r_axis_closest = ((struct Object_Nearest2dPrecalc *)userdata)->r_axis_closest;
+ return r_axis_closest[axis];
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
+/** \name Internal Object Snapping API
+ * \{ */
+
static bool snapArmature(
- Object *ob, bArmature *arm, float obmat[4][4],
- const short snap_to, const bool is_persp,
- const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2],
+ const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4],
+ const short snap_to, const float origin[3], const float dir[3],
+ const float mval[2], const enum eViewProj view_proj, const float depth_range[2],
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
- float imat[4][4];
- float ray_origin_local[3], ray_normal_local[3];
bool retval = false;
- invert_m4_m4(imat, obmat);
+ float ray_start_local[3], ray_normal_local[3];
+ if (snap_to != SCE_SNAP_MODE_VERTEX) {
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
- mul_v3_m4v3(ray_origin_local, imat, ray_origin);
- mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal);
+ copy_v3_v3(ray_start_local, origin);
+ copy_v3_v3(ray_normal_local, dir);
+ mul_m4_v3(imat, ray_start_local);
+ mul_mat3_m4_v3(imat, ray_normal_local);
+ }
- float ob_scale[3];
- mat4_to_size(ob_scale, obmat);
+ PreDefProject projectdefs;
+ precalc_project(&projectdefs, ar, *dist_px, obmat);
if (arm->edbo) {
- EditBone *eBone;
-
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) {
if (eBone->layer & arm->layer) {
/* skip hidden or moving (selected) bones */
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
- retval |= test_vert(
- eBone->head, NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
- retval |= test_vert(
- eBone->tail, NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, eBone->head, view_proj, mval, depth_range, r_loc);
+ retval |= test_projected_vert_dist(
+ &projectdefs, eBone->tail, view_proj, mval, depth_range, r_loc);
break;
case SCE_SNAP_MODE_EDGE:
- retval |= test_edge(
- eBone->head, eBone->tail, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_edge_dist(
+ &projectdefs, eBone->head, eBone->tail, ray_start_local, ray_normal_local,
+ view_proj, mval, depth_range, r_loc);
break;
}
}
@@ -360,11 +778,8 @@ static bool snapArmature(
}
}
else if (ob->pose && ob->pose->chanbase.first) {
- bPoseChannel *pchan;
- Bone *bone;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- bone = pchan->bone;
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ Bone *bone = pchan->bone;
/* skip hidden bones */
if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
const float *head_vec = pchan->pose_head;
@@ -372,26 +787,22 @@ static bool snapArmature(
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
- retval |= test_vert(
- head_vec, NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
- retval |= test_vert(
- tail_vec, NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, head_vec, view_proj, mval, depth_range, r_loc);
+ retval |= test_projected_vert_dist(
+ &projectdefs, tail_vec, view_proj, mval, depth_range, r_loc);
break;
case SCE_SNAP_MODE_EDGE:
- retval |= test_edge(
- head_vec, tail_vec, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_edge_dist(
+ &projectdefs, head_vec, tail_vec, ray_start_local, ray_normal_local,
+ view_proj, mval, depth_range, r_loc);
break;
}
}
}
}
if (retval) {
+ *dist_px = sqrtf(projectdefs.dist_px_sq);
mul_m4_v3(obmat, r_loc);
return true;
}
@@ -399,39 +810,26 @@ static bool snapArmature(
}
static bool snapCurve(
- Object *ob, Curve *cu, float obmat[4][4],
- const short snap_to, const bool is_persp,
- const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2],
+ const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4],
+ const short snap_to, const float mval[2], const enum eViewProj view_proj,
+ const float depth_range[2],
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
- float imat[4][4];
- float ray_origin_local[3], ray_normal_local[3];
bool retval = false;
- int u;
-
- Nurb *nu;
/* only vertex snapping mode (eg control points and handles) supported for now) */
if (snap_to != SCE_SNAP_MODE_VERTEX) {
return retval;
}
- invert_m4_m4(imat, obmat);
-
- copy_v3_v3(ray_origin_local, ray_origin);
- copy_v3_v3(ray_normal_local, ray_normal);
-
- mul_m4_v3(imat, ray_origin_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
-
- float ob_scale[3];
- mat4_to_size(ob_scale, obmat);
+ PreDefProject projectdefs;
+ precalc_project(&projectdefs, ar, *dist_px, obmat);
- for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
- for (u = 0; u < nu->pntsu; u++) {
+ for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) {
+ for (int u = 0; u < nu->pntsu; u++) {
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
@@ -441,26 +839,20 @@ static bool snapCurve(
if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) {
break;
}
- retval |= test_vert(
- nu->bezt[u].vec[1], NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
/* don't snap if handle is selected (moving), or if it is aligning to a moving handle */
if (!(nu->bezt[u].f1 & SELECT) &&
!(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT))
{
- retval |= test_vert(
- nu->bezt[u].vec[0], NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bezt[u].vec[0], view_proj, mval, depth_range, r_loc);
}
if (!(nu->bezt[u].f3 & SELECT) &&
!(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT))
{
- retval |= test_vert(
- nu->bezt[u].vec[2], NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bezt[u].vec[2], view_proj, mval, depth_range, r_loc);
}
}
else {
@@ -468,26 +860,20 @@ static bool snapCurve(
if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) {
break;
}
- retval |= test_vert(
- nu->bp[u].vec, NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
}
}
else {
/* curve is not visible outside editmode if nurb length less than two */
if (nu->pntsu > 1) {
if (nu->bezt) {
- retval |= test_vert(
- nu->bezt[u].vec[1], NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc);
}
else {
- retval |= test_vert(
- nu->bp[u].vec, NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ retval |= test_projected_vert_dist(
+ &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc);
}
}
}
@@ -499,6 +885,7 @@ static bool snapCurve(
}
}
if (retval) {
+ *dist_px = sqrtf(projectdefs.dist_px_sq);
mul_m4_v3(obmat, r_loc);
return true;
}
@@ -507,11 +894,11 @@ static bool snapCurve(
/* may extend later (for now just snaps to empty center) */
static bool snapEmpty(
- Object *ob, float obmat[4][4],
- const short snap_to, const bool is_persp,
- const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2],
+ const ARegion *ar, Object *ob, float obmat[4][4],
+ const short snap_to, const float mval[2], const enum eViewProj view_proj,
+ const float depth_range[2],
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
@@ -520,17 +907,19 @@ static bool snapEmpty(
if (ob->transflag & OB_DUPLI) {
return retval;
}
+
/* for now only vertex supported */
switch (snap_to) {
case SCE_SNAP_MODE_VERTEX:
{
- float ob_loc[3], ob_scale[3] = {1.0, 1.0, 1.0};
- copy_v3_v3(ob_loc, obmat[3]);
-
- retval |= test_vert(
- ob_loc, NULL, ray_origin, ray_normal,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
+ PreDefProject projectdefs;
+ precalc_project(&projectdefs, ar, *dist_px, NULL);
+ float tmp_co[3];
+ copy_v3_v3(tmp_co, obmat[3]);
+ if (test_projected_vert_dist(&projectdefs, tmp_co, view_proj, mval, depth_range, r_loc)) {
+ *dist_px = sqrtf(projectdefs.dist_px_sq);
+ retval = true;
+ }
break;
}
default:
@@ -541,19 +930,23 @@ static bool snapEmpty(
}
static bool snapCamera(
- Scene *scene, Object *object, float obmat[4][4],
- const short snap_to, const bool is_persp,
- const float ray_origin[3], const float ray_normal[3], const float ray_depth_range[2],
+ const SnapObjectContext *sctx, Object *object, float obmat[4][4],
+ const short snap_to, const float mval[2], const enum eViewProj view_proj,
+ const float depth_range[2],
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *dist_px,
/* return args */
float r_loc[3], float *UNUSED(r_no))
{
+ Scene *scene = sctx->scene;
+
+ PreDefProject projectdefs;
+ precalc_project(&projectdefs, sctx->v3d_data.ar, *dist_px, NULL);
+
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
bool retval = false;
MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
MovieTracking *tracking;
- float ray_origin_local[3], ray_normal_local[3];
if (clip == NULL) {
return retval;
@@ -584,9 +977,6 @@ static bool snapCamera(
reconstructed_camera_imat[4][4];
float (*vertex_obmat)[4];
- copy_v3_v3(ray_origin_local, ray_origin);
- copy_v3_v3(ray_normal_local, ray_normal);
-
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object,
CFRA, reconstructed_camera_mat);
@@ -603,26 +993,16 @@ static bool snapCamera(
copy_v3_v3(bundle_pos, track->bundle_pos);
if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
- mul_m4_v3(orig_camera_imat, ray_origin_local);
- mul_mat3_m4_v3(orig_camera_imat, ray_normal_local);
vertex_obmat = orig_camera_mat;
}
else {
mul_m4_v3(reconstructed_camera_imat, bundle_pos);
- mul_m4_v3(imat, ray_origin_local);
- mul_mat3_m4_v3(imat, ray_normal_local);
vertex_obmat = obmat;
}
- float ob_scale[3];
- mat4_to_size(ob_scale, vertex_obmat);
-
- retval |= test_vert(
- bundle_pos, NULL, ray_origin_local, ray_normal_local,
- ray_depth_range, ob_scale, is_persp, ray_depth, dist_to_ray_sq,
- r_loc, NULL);
-
- mul_m4_v3(vertex_obmat, r_loc);
+ mul_m4_v3(vertex_obmat, bundle_pos);
+ retval |= test_projected_vert_dist(
+ &projectdefs, bundle_pos, view_proj, mval, depth_range, r_loc);
}
}
@@ -632,7 +1012,11 @@ static bool snapCamera(
break;
}
- return retval;
+ if (retval) {
+ *dist_px = sqrtf(projectdefs.dist_px_sq);
+ return true;
+ }
+ return false;
}
static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
@@ -643,44 +1027,45 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt)
struct NearestDM_Data {
void *bvhdata;
- bool is_persp;
- const float *ray_depth_range;
-
+ const float *depth_range;
float *ray_depth;
};
-static void test_vert_depth_cb(
+static void test_vert_ray_dist_cb(
void *userdata, const float origin[3], const float dir[3],
const float scale[3], int index, BVHTreeNearest *nearest)
{
struct NearestDM_Data *ndata = userdata;
- const BVHTreeFromMesh *data = ndata->bvhdata;
- const MVert *vert = data->vert + index;
+ const struct BVHTreeFromMeshType *data = ndata->bvhdata;
+
+ const float *co = get_vert_co(data, index);
- if (test_vert(
- vert->co, NULL, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
- ndata->ray_depth, &nearest->dist_sq,
- nearest->co, NULL))
+ if (test_vert_dist(
+ co, origin, dir, ndata->depth_range,
+ scale, ndata->ray_depth, &nearest->dist_sq,
+ nearest->co))
{
- normal_short_to_float_v3(nearest->no, vert->no);
+ copy_vert_no(data, index, nearest->no);
nearest->index = index;
}
}
-static void test_edge_depth_cb(
+static void test_edge_ray_dist_cb(
void *userdata, const float origin[3], const float dir[3],
const float scale[3], int index, BVHTreeNearest *nearest)
{
struct NearestDM_Data *ndata = userdata;
- const BVHTreeFromMesh *data = ndata->bvhdata;
- const MVert *vert = data->vert;
- const MEdge *edge = data->edge + index;
-
- if (test_edge(
- vert[edge->v1].co, vert[edge->v2].co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
- ndata->ray_depth, &nearest->dist_sq,
- nearest->co, nearest->no))
+ BVHTreeFromMeshType *data = ndata->bvhdata;
+
+ const float *v_pair[2];
+ get_edge_verts(data, index, v_pair);
+
+ if (test_edge_dist(
+ v_pair[0], v_pair[1], origin, dir, ndata->depth_range,
+ scale, ndata->ray_depth, &nearest->dist_sq,
+ nearest->co))
{
+ sub_v3_v3v3(nearest->no, v_pair[0], v_pair[1]);
nearest->index = index;
}
}
@@ -688,10 +1073,11 @@ static void test_edge_depth_cb(
static bool snapDerivedMesh(
SnapObjectContext *sctx,
Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index,
- const short snap_to, const bool is_persp, bool do_bb,
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2],
+ const short snap_to, const float mval[2], const enum eViewProj view_proj, bool do_bb,
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ const float depth_range[2],
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
ListBase *r_hit_list)
@@ -703,7 +1089,7 @@ static bool snapDerivedMesh(
return retval;
}
}
- if (snap_to == SCE_SNAP_MODE_EDGE) {
+ else if (snap_to == SCE_SNAP_MODE_EDGE) {
if (dm->getNumEdges(dm) == 0) {
return retval;
}
@@ -715,7 +1101,7 @@ static bool snapDerivedMesh(
}
{
- bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && sctx->use_v3d && !is_persp;
+ bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && (view_proj == VIEW_PROJ_ORTHO);
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
@@ -823,28 +1209,30 @@ static bool snapDerivedMesh(
}
}
+ if (!treedata || !treedata->tree) {
+ return retval;
+ }
+
if (snap_to == SCE_SNAP_MODE_FACE) {
/* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already
* been *inside* boundbox, leading to snap failures (see T38409).
* Note also ar might be null (see T38435), in this case we assume ray_start is ok!
*/
- if (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */
+ if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
if (need_ray_start_correction_init) {
/* We *need* a reasonably valid len_diff in this case.
* Use BHVTree to find the closest face from ray_start_local.
*/
- if (treedata && treedata->tree != NULL) {
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
- if (nearest.index != -1) {
- float dvec[3];
- sub_v3_v3v3(dvec, nearest.co, ray_start_local);
- len_diff = dot_v3v3(dvec, ray_normal_local);
- }
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata);
+ if (nearest.index != -1) {
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
}
}
float ray_org_local[3];
@@ -856,8 +1244,8 @@ static bool snapDerivedMesh(
* away ray_start values (as returned in case of ortho view3d), see T38358.
*/
len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff + ray_depth_range[0]);
+ madd_v3_v3v3fl(
+ ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale);
local_depth -= len_diff;
}
else {
@@ -874,24 +1262,19 @@ static bool snapDerivedMesh(
data.local_scale = local_scale;
data.ob = ob;
data.ob_uuid = ob_index;
- data.dm = dm;
data.hit_list = r_hit_list;
data.retval = retval;
BLI_bvhtree_ray_cast_all(
- treedata->tree, ray_start_local, ray_normal_local, 0.0f,
- *ray_depth, raycast_all_cb, &data);
+ treedata->tree, ray_start_local, ray_normal_local, 0.0f,
+ *ray_depth, raycast_all_cb, &data);
retval = data.retval;
}
else {
- BVHTreeRayHit hit;
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
- hit.index = -1;
- hit.dist = local_depth;
-
- if (treedata->tree &&
- BLI_bvhtree_ray_cast(
+ if (BLI_bvhtree_ray_cast(
treedata->tree, ray_start_local, ray_normal_local, 0.0f,
&hit, treedata->raycast_callback, treedata) != -1)
{
@@ -900,12 +1283,15 @@ static bool snapDerivedMesh(
if (hit.dist <= *ray_depth) {
*ray_depth = hit.dist;
copy_v3_v3(r_loc, hit.co);
- copy_v3_v3(r_no, hit.no);
/* back to worldspace */
mul_m4_v3(obmat, r_loc);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
+
+ if (r_no) {
+ copy_v3_v3(r_no, hit.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
retval = true;
@@ -917,51 +1303,78 @@ static bool snapDerivedMesh(
}
}
else {
- /* Vert & edge use nearly identical logic. */
- BLI_assert(ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE));
+ const ARegion *ar = sctx->v3d_data.ar;
float ray_org_local[3];
-
copy_v3_v3(ray_org_local, ray_origin);
mul_m4_v3(imat, ray_org_local);
- BVHTreeNearest nearest;
+ BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_MESH};
- nearest.index = -1;
- nearest.dist_sq = *dist_to_ray_sq;
+ if (view_proj == VIEW_PROJ_PERSP) {
+ Object_Nearest2dPrecalc neasrest_precalc;
+ neasrest_precalc.userdata = &treedata_type;
+ neasrest_precalc.index = -1;
- struct NearestDM_Data userdata;
- userdata.bvhdata = treedata;
- userdata.is_persp = is_persp;
- userdata.ray_depth_range = ray_depth_range;
- userdata.ray_depth = ray_depth;
+ nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
+ ray_org_local, ray_normal_local, mval, depth_range);
- float ob_scale[3];
- mat4_to_size(ob_scale, obmat);
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
- BVHTree_NearestToRayCallback callback =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- test_vert_depth_cb : test_edge_depth_cb;
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
- if (treedata->tree &&
- (is_persp ?
- BLI_bvhtree_find_nearest_to_ray_angle(
- treedata->tree, ray_org_local, ray_normal_local,
- true, ob_scale, &nearest, callback, &userdata) :
- BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_org_local, ray_normal_local,
- true, ob_scale, &nearest, callback, &userdata)) != -1)
- {
- copy_v3_v3(r_loc, nearest.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, nearest.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
+ if (neasrest_precalc.index != -1) {
+ copy_v3_v3(r_loc, neasrest_precalc.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest_precalc.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
+
+ retval = true;
}
- *dist_to_ray_sq = nearest.dist_sq;
+ }
+ else {
+ BVHTreeNearest nearest;
- retval = true;
+ nearest.index = -1;
+ float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px);
+ nearest.dist_sq = SQUARE(dist_3d);
+
+
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = &treedata_type;
+ userdata.depth_range = depth_range;
+ userdata.ray_depth = ray_depth;
+
+ BVHTree_NearestToRayCallback cb_test_ray_dist =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ test_vert_ray_dist_cb : test_edge_ray_dist_cb;
+
+ if (BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ true, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1)
+ {
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px *= sqrtf(nearest.dist_sq) / dist_3d;
+
+ retval = true;
+ }
}
}
@@ -975,47 +1388,14 @@ static bool snapDerivedMesh(
return retval;
}
-static void test_bmvert_depth_cb(
- void *userdata, const float origin[3], const float dir[3],
- const float scale[3], int index, BVHTreeNearest *nearest)
-{
- struct NearestDM_Data *ndata = userdata;
- const BMEditMesh *em = ndata->bvhdata;
- BMVert *eve = BM_vert_at_index(em->bm, index);
-
- if (test_vert(
- eve->co, eve->no, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
- ndata->ray_depth, &nearest->dist_sq,
- nearest->co, nearest->no))
- {
- nearest->index = index;
- }
-}
-
-static void test_bmedge_depth_cb(
- void *userdata, const float origin[3], const float dir[3],
- const float scale[3], int index, BVHTreeNearest *nearest)
-{
- struct NearestDM_Data *ndata = userdata;
- const BMEditMesh *em = ndata->bvhdata;
- BMEdge *eed = BM_edge_at_index(em->bm, index);
-
- if (test_edge(
- eed->v1->co, eed->v2->co, origin, dir, ndata->ray_depth_range, scale, ndata->is_persp,
- ndata->ray_depth, &nearest->dist_sq,
- nearest->co, nearest->no))
- {
- nearest->index = index;
- }
-}
-
static bool snapEditMesh(
SnapObjectContext *sctx,
Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index,
- const short snap_to, const bool is_persp,
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2],
+ const short snap_to, const float mval[2], const enum eViewProj view_proj,
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ const float depth_range[2],
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
ListBase *r_hit_list)
@@ -1143,6 +1523,10 @@ static bool snapEditMesh(
}
}
+ if (!treedata || !treedata->tree) {
+ return retval;
+ }
+
if (snap_to == SCE_SNAP_MODE_FACE) {
float ray_start_local[3];
copy_v3_v3(ray_start_local, ray_start);
@@ -1160,35 +1544,33 @@ static bool snapEditMesh(
* Note also ar might be null (see T38435), in this case we assume ray_start is ok!
*/
float len_diff = 0.0f;
- if (sctx->use_v3d && !is_persp) { /* do_ray_start_correction */
+ if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */
/* We *need* a reasonably valid len_diff in this case.
* Use BHVTree to find the closest face from ray_start_local.
*/
- if (treedata && treedata->tree != NULL) {
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- /* Compute and store result. */
- if (BLI_bvhtree_find_nearest(
- treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1)
- {
- float dvec[3];
- sub_v3_v3v3(dvec, nearest.co, ray_start_local);
- len_diff = dot_v3v3(dvec, ray_normal_local);
- float ray_org_local[3];
-
- copy_v3_v3(ray_org_local, ray_origin);
- mul_m4_v3(imat, ray_org_local);
-
- /* We pass a temp ray_start, set from object's boundbox,
- * to avoid precision issues with very far away ray_start values
- * (as returned in case of ortho view3d), see T38358.
- */
- len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
- madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local,
- len_diff + ray_depth_range[0]);
- local_depth -= len_diff;
- }
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ if (BLI_bvhtree_find_nearest(
+ treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1)
+ {
+ float dvec[3];
+ sub_v3_v3v3(dvec, nearest.co, ray_start_local);
+ len_diff = dot_v3v3(dvec, ray_normal_local);
+ float ray_org_local[3];
+
+ copy_v3_v3(ray_org_local, ray_origin);
+ mul_m4_v3(imat, ray_org_local);
+
+ /* We pass a temp ray_start, set from object's boundbox,
+ * to avoid precision issues with very far away ray_start values
+ * (as returned in case of ortho view3d), see T38358.
+ */
+ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */
+ madd_v3_v3v3fl(
+ ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0] * local_scale);
+ local_depth -= len_diff;
}
}
if (r_hit_list) {
@@ -1202,7 +1584,6 @@ static bool snapEditMesh(
data.local_scale = local_scale;
data.ob = ob;
data.ob_uuid = ob_index;
- data.dm = NULL;
data.hit_list = r_hit_list;
data.retval = retval;
@@ -1213,13 +1594,9 @@ static bool snapEditMesh(
retval = data.retval;
}
else {
- BVHTreeRayHit hit;
+ BVHTreeRayHit hit = {.index = -1, .dist = local_depth};
- hit.index = -1;
- hit.dist = local_depth;
-
- if (treedata->tree &&
- BLI_bvhtree_ray_cast(
+ if (BLI_bvhtree_ray_cast(
treedata->tree, ray_start_local, ray_normal_local, 0.0f,
&hit, treedata->raycast_callback, treedata) != -1)
{
@@ -1228,12 +1605,15 @@ static bool snapEditMesh(
if (hit.dist <= *ray_depth) {
*ray_depth = hit.dist;
copy_v3_v3(r_loc, hit.co);
- copy_v3_v3(r_no, hit.no);
/* back to worldspace */
mul_m4_v3(obmat, r_loc);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
+
+ if (r_no) {
+ copy_v3_v3(r_no, hit.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
retval = true;
@@ -1245,51 +1625,78 @@ static bool snapEditMesh(
}
}
else {
- /* Vert & edge use nearly identical logic. */
- BLI_assert(ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE));
+ const ARegion *ar = sctx->v3d_data.ar;
float ray_org_local[3];
-
copy_v3_v3(ray_org_local, ray_origin);
mul_m4_v3(imat, ray_org_local);
- BVHTreeNearest nearest;
+ BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_EDIT_MESH};
- nearest.index = -1;
- nearest.dist_sq = *dist_to_ray_sq;
+ if (view_proj == VIEW_PROJ_PERSP) {
+ Object_Nearest2dPrecalc neasrest_precalc;
+ neasrest_precalc.userdata = &treedata_type;
+ neasrest_precalc.index = -1;
- struct NearestDM_Data userdata;
- userdata.bvhdata = em;
- userdata.is_persp = is_persp;
- userdata.ray_depth_range = ray_depth_range;
- userdata.ray_depth = ray_depth;
+ nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat,
+ ray_org_local, ray_normal_local, mval, depth_range);
- float ob_scale[3];
- mat4_to_size(ob_scale, obmat);
+ BVHTree_WalkLeafCallback cb_walk_leaf =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge;
- BVHTree_NearestToRayCallback callback =
- (snap_to == SCE_SNAP_MODE_VERTEX) ?
- test_bmvert_depth_cb : test_bmedge_depth_cb;
+ BLI_bvhtree_walk_dfs(
+ treedata->tree,
+ cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc);
- if (treedata->tree &&
- (is_persp ?
- BLI_bvhtree_find_nearest_to_ray_angle(
- treedata->tree, ray_org_local, ray_normal_local,
- false, ob_scale, &nearest, callback, &userdata) :
- BLI_bvhtree_find_nearest_to_ray(
- treedata->tree, ray_org_local, ray_normal_local,
- false, ob_scale, &nearest, callback, &userdata)) != -1)
- {
- copy_v3_v3(r_loc, nearest.co);
- mul_m4_v3(obmat, r_loc);
- if (r_no) {
- copy_v3_v3(r_no, nearest.no);
- mul_m3_v3(timat, r_no);
- normalize_v3(r_no);
+ if (neasrest_precalc.index != -1) {
+ copy_v3_v3(r_loc, neasrest_precalc.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, neasrest_precalc.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq);
+
+ retval = true;
}
- *dist_to_ray_sq = nearest.dist_sq;
+ }
+ else {
+ BVHTreeNearest nearest;
- retval = true;
+ nearest.index = -1;
+ float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px);
+ nearest.dist_sq = SQUARE(dist_3d);
+
+
+ float ob_scale[3];
+ mat4_to_size(ob_scale, obmat);
+
+ struct NearestDM_Data userdata;
+ userdata.bvhdata = &treedata_type;
+ userdata.depth_range = depth_range;
+ userdata.ray_depth = ray_depth;
+
+ BVHTree_NearestToRayCallback cb_test_ray_dist =
+ (snap_to == SCE_SNAP_MODE_VERTEX) ?
+ test_vert_ray_dist_cb : test_edge_ray_dist_cb;
+
+ if (BLI_bvhtree_find_nearest_to_ray(
+ treedata->tree, ray_org_local, ray_normal_local,
+ false, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1)
+ {
+ copy_v3_v3(r_loc, nearest.co);
+ mul_m4_v3(obmat, r_loc);
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ mul_m3_v3(timat, r_no);
+ normalize_v3(r_no);
+ }
+ *dist_px *= sqrtf(nearest.dist_sq) / dist_3d;
+
+ retval = true;
+ }
}
}
@@ -1305,26 +1712,28 @@ static bool snapEditMesh(
/**
* \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
- * \param ray_depth_range:
- * - 0: distance from the ray_origin to the clipping plane min (can be negative).
- * - 1: maximum distance, elements outside this are ignored.
- * \param ray_depth: maximum depth allowed for r_co.
*
* \note Duplicate args here are documented at #snapObjectsRay
*/
static bool snapObject(
SnapObjectContext *sctx,
Object *ob, float obmat[4][4], const unsigned int ob_index,
- bool use_obedit, const short snap_to,
- const float ray_origin[3], const float ray_start[3], const float ray_normal[3], const float ray_depth_range[2],
+ bool use_obedit, const short snap_to, const float mval[2],
+ const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ const float depth_range[2],
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
ListBase *r_hit_list)
{
- const bool is_persp = sctx->use_v3d && ((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp;
+ const enum eViewProj view_proj =
+ ((sctx->use_v3d == false) || (mval == NULL)) ? VIEW_PROJ_NONE :
+ (((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO);
+
+ const ARegion *ar = sctx->v3d_data.ar;
+
bool retval = false;
if (ob->type == OB_MESH) {
@@ -1334,9 +1743,9 @@ static bool snapObject(
em = BKE_editmesh_from_object(ob);
retval = snapEditMesh(
sctx, ob, em, obmat, ob_index,
- snap_to, is_persp,
- ray_origin, ray_start, ray_normal, ray_depth_range,
- ray_depth, dist_to_ray_sq,
+ snap_to, mval, view_proj,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no, r_index,
r_hit_list);
}
@@ -1353,42 +1762,43 @@ static bool snapObject(
}
retval = snapDerivedMesh(
sctx, ob, dm, obmat, ob_index,
- snap_to, is_persp, true,
- ray_origin, ray_start, ray_normal, ray_depth_range,
- ray_depth, dist_to_ray_sq,
+ snap_to, mval, view_proj, true,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no,
r_index, r_hit_list);
dm->release(dm);
}
}
- else if (ob->type == OB_ARMATURE) {
- retval = snapArmature(
- ob, ob->data, obmat, snap_to, is_persp,
- ray_origin, ray_normal, ray_depth_range,
- ray_depth, dist_to_ray_sq,
- r_loc, r_no);
- }
- else if (ob->type == OB_CURVE) {
- retval = snapCurve(
- ob, ob->data, obmat, snap_to, is_persp,
- ray_origin, ray_normal, ray_depth_range,
- ray_depth, dist_to_ray_sq,
- r_loc, r_no);
- }
- else if (ob->type == OB_EMPTY) {
- retval = snapEmpty(
- ob, obmat, snap_to, is_persp,
- ray_origin, ray_normal, ray_depth_range,
- ray_depth, dist_to_ray_sq,
- r_loc, r_no);
- }
- else if (ob->type == OB_CAMERA) {
- retval = snapCamera(
- sctx->scene, ob, obmat, snap_to, is_persp,
- ray_origin, ray_normal, ray_depth_range,
- ray_depth, dist_to_ray_sq,
- r_loc, r_no);
+ else if (snap_to != SCE_SNAP_MODE_FACE) {
+ if (ob->type == OB_ARMATURE) {
+ retval = snapArmature(
+ ar, ob, ob->data, obmat, snap_to, ray_origin, ray_normal,
+ mval, view_proj, depth_range, dist_px,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_CURVE) {
+ retval = snapCurve(
+ ar, ob, ob->data, obmat, snap_to, mval, view_proj,
+ depth_range,
+ dist_px,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_EMPTY) {
+ retval = snapEmpty(
+ ar, ob, obmat, snap_to, mval, view_proj,
+ depth_range,
+ dist_px,
+ r_loc, r_no);
+ }
+ else if (ob->type == OB_CAMERA) {
+ retval = snapCamera(
+ sctx, ob, obmat, snap_to, mval, view_proj,
+ depth_range,
+ dist_px,
+ r_loc, r_no);
+ }
}
if (retval) {
@@ -1414,16 +1824,18 @@ static bool snapObject(
* \param snap_select: from enum SnapSelect.
*
* \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping.
+ * \param mval: Mouse coords.
+ * When NULL, ray-casting is handled without any projection matrix correction.
* \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min.
* \param ray_start: ray_origin moved for the start clipping plane (clip_min).
* \param ray_normal: Unit length direction of the ray.
+ * \param depth_range: distances of clipe plane min and clip plane max;
*
* Read/Write Args
* ---------------
*
* \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored.
- * \param dist_to_ray_sq: Real distance (3D) or Tangent (view cone radius at distance 1.0) squared.
- * resulting of the function #dist_px_to_dist3d_or_tangent.
+ * \param dist_px: Maximum threshold distance (in pixels).
*
* Output Args
* -----------
@@ -1440,10 +1852,11 @@ static bool snapObject(
static bool snapObjectsRay(
SnapObjectContext *sctx,
const unsigned short snap_to, const SnapSelect snap_select,
- const bool use_object_edit_cage,
+ const bool use_object_edit_cage, const float mval[2],
const float ray_origin[3], const float ray_start[3], const float ray_normal[3],
+ const float depth_range[2],
/* read/write args */
- float *ray_depth, float *dist_to_ray_sq,
+ float *ray_depth, float *dist_px,
/* return args */
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4],
@@ -1451,14 +1864,6 @@ static bool snapObjectsRay(
{
bool retval = false;
- float dvec[3];
- sub_v3_v3v3(dvec, ray_start, ray_origin);
-
- const float ray_depth_range[2] = {
- dot_v3v3(dvec, ray_normal),
- *ray_depth,
- };
-
unsigned int ob_index = 0;
Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL;
@@ -1473,9 +1878,9 @@ static bool snapObjectsRay(
retval |= snapObject(
sctx, ob, ob->obmat, ob_index++,
- false, snap_to,
- ray_origin, ray_start, ray_normal, ray_depth_range,
- ray_depth, dist_to_ray_sq,
+ false, snap_to, mval,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1509,9 +1914,9 @@ static bool snapObjectsRay(
retval |= snapObject(
sctx, dupli_snap, dupli_ob->mat, ob_index++,
- use_obedit_dupli, snap_to,
- ray_origin, ray_start, ray_normal, ray_depth_range,
- ray_depth, dist_to_ray_sq,
+ use_obedit_dupli, snap_to, mval,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
@@ -1523,9 +1928,9 @@ static bool snapObjectsRay(
retval |= snapObject(
sctx, ob_snap, ob->obmat, ob_index++,
- use_obedit, snap_to,
- ray_origin, ray_start, ray_normal, ray_depth_range,
- ray_depth, dist_to_ray_sq,
+ use_obedit, snap_to, mval,
+ ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list);
}
}
@@ -1632,13 +2037,12 @@ bool ED_transform_snap_object_project_ray_ex(
float r_loc[3], float r_no[3], int *r_index,
Object **r_ob, float r_obmat[4][4])
{
- float dist_to_ray_sq = 0.0f;
-
+ const float depth_range[2] = {0.0f, FLT_MAX};
return snapObjectsRay(
sctx,
- snap_to, params->snap_select, params->use_object_edit_cage,
- ray_start, ray_start, ray_normal,
- ray_depth, &dist_to_ray_sq,
+ snap_to, params->snap_select, params->use_object_edit_cage, NULL,
+ ray_start, ray_start, ray_normal, depth_range,
+ ray_depth, NULL,
r_loc, r_no, r_index, r_ob, r_obmat, NULL);
}
@@ -1657,8 +2061,7 @@ bool ED_transform_snap_object_project_ray_all(
float ray_depth, bool sort,
ListBase *r_hit_list)
{
- float dist_to_ray_sq = 0.0f;
-
+ const float depth_range[2] = {0.0f, FLT_MAX};
if (ray_depth == -1.0f) {
ray_depth = BVH_RAYCAST_DIST_MAX;
}
@@ -1669,9 +2072,9 @@ bool ED_transform_snap_object_project_ray_all(
bool retval = snapObjectsRay(
sctx,
- snap_to, params->snap_select, params->use_object_edit_cage,
- ray_start, ray_start, ray_normal,
- &ray_depth, &dist_to_ray_sq,
+ snap_to, params->snap_select, params->use_object_edit_cage, NULL,
+ ray_start, ray_start, ray_normal, depth_range,
+ &ray_depth, NULL,
NULL, NULL, NULL, NULL, NULL,
r_hit_list);
@@ -1726,11 +2129,6 @@ bool ED_transform_snap_object_project_ray(
ray_depth = &ray_depth_fallback;
}
- float no_fallback[3];
- if (r_no == NULL) {
- r_no = no_fallback;
- }
-
return transform_snap_context_project_ray_impl(
sctx,
params,
@@ -1749,11 +2147,6 @@ static bool transform_snap_context_project_view3d_mixed_impl(
float ray_depth = BVH_RAYCAST_DIST_MAX;
bool is_hit = false;
- float r_no_dummy[3];
- if (r_no == NULL) {
- r_no = r_no_dummy;
- }
-
const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE};
BLI_assert(snap_to_flag != 0);
@@ -1780,21 +2173,6 @@ static bool transform_snap_context_project_view3d_mixed_impl(
}
/**
- * From a threshold (maximum distance to snap in pixels) returns:
- *
- * - The *real* distance (3D) if you are in orthographic-view.
- * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view.
- */
-static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px)
-{
- const RegionView3D *rv3d = ar->regiondata;
- if (ar->winx >= ar->winy)
- return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0];
- else
- return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1];
-}
-
-/**
* Convenience function for performing snapping.
*
* Given a 2D region value, snap to vert/edge/face.
@@ -1830,55 +2208,37 @@ bool ED_transform_snap_object_project_view3d_ex(
float *ray_depth,
float r_loc[3], float r_no[3], int *r_index)
{
- float ray_start[3], ray_normal[3], ray_origin[3];
+ float ray_origin[3], ray_start[3], ray_normal[3], depth_range[2], ray_end[3];
- float ray_depth_fallback;
- if (ray_depth == NULL) {
- ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
- ray_depth = &ray_depth_fallback;
- }
+ const ARegion *ar = sctx->v3d_data.ar;
+ const RegionView3D *rv3d = ar->regiondata;
- if (!ED_view3d_win_to_ray_ex(
- sctx->v3d_data.ar, sctx->v3d_data.v3d,
- mval, ray_origin, ray_normal, ray_start, true))
- {
+ ED_view3d_win_to_origin(ar, mval, ray_origin);
+ ED_view3d_win_to_vector(ar, mval, ray_normal);
+
+ ED_view3d_clip_range_get(
+ sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata,
+ &depth_range[0], &depth_range[1], false);
+
+ madd_v3_v3v3fl(ray_start, ray_origin, ray_normal, depth_range[0]);
+ madd_v3_v3v3fl(ray_end, ray_origin, ray_normal, depth_range[1]);
+
+ if (!ED_view3d_clip_segment(rv3d, ray_start, ray_end)) {
return false;
}
- float radius, dist_to_ray_sq = 0.0f;
- if (dist_px) {
- radius = dist_px_to_dist3d_or_tangent(sctx->v3d_data.ar, *dist_px);
- /**
- * Workaround to use of cone (Instead of project the radius on view plane):
- * In perspective view, the radius of the cone may decrease depending on the ray direction.
- * This is more evident with small values of the `Viewport lens angle`.
- * The threshold becomes distorted that way.
- */
- RegionView3D *rv3d = sctx->v3d_data.ar->regiondata;
- if (rv3d->is_persp) {
- float view_dir[3];
- negate_v3_v3(view_dir, rv3d->viewinv[2]);
- normalize_v3(view_dir);
- radius *= dot_v3v3(ray_normal, view_dir);
- }
-
- dist_to_ray_sq = SQUARE(radius);
+ float ray_depth_fallback;
+ if (ray_depth == NULL) {
+ ray_depth_fallback = BVH_RAYCAST_DIST_MAX;
+ ray_depth = &ray_depth_fallback;
}
- if (snapObjectsRay(
+ return snapObjectsRay(
sctx,
snap_to, params->snap_select, params->use_object_edit_cage,
- ray_origin, ray_start, ray_normal,
- ray_depth, &dist_to_ray_sq,
- r_loc, r_no, r_index, NULL, NULL, NULL))
- {
- if (dist_px) {
- *dist_px *= sqrtf(dist_to_ray_sq) / radius;
- }
- return true;
- }
-
- return false;
+ mval, ray_origin, ray_start, ray_normal, depth_range,
+ ray_depth, dist_px,
+ r_loc, r_no, r_index, NULL, NULL, NULL);
}
bool ED_transform_snap_object_project_view3d(
diff --git a/source/blender/freestyle/intern/stroke/Curve.cpp b/source/blender/freestyle/intern/stroke/Curve.cpp
index 69c5dcdfe28..a8dbce84971 100644
--- a/source/blender/freestyle/intern/stroke/Curve.cpp
+++ b/source/blender/freestyle/intern/stroke/Curve.cpp
@@ -133,7 +133,7 @@ iA_B_eq_iB_A:
//_t2d = t3;
_t2d = t2 * t3;
}
- else if ((iA->getPoint2D() - iA->getPoint2D()).norm() < 1.0e-6) {
+ else if ((iA->getPoint2D() - iB->getPoint2D()).norm() < 1.0e-6) {
__A = iB->A();
__B = iB->B();
//_t2d = t3;
diff --git a/source/blender/freestyle/intern/view_map/Functions1D.cpp b/source/blender/freestyle/intern/view_map/Functions1D.cpp
index 11e0cc37d4d..8f16f78cb10 100644
--- a/source/blender/freestyle/intern/view_map/Functions1D.cpp
+++ b/source/blender/freestyle/intern/view_map/Functions1D.cpp
@@ -104,7 +104,7 @@ int QuantitativeInvisibilityF1D::operator()(Interface1D& inter)
}
FEdge *fe = dynamic_cast<FEdge*>(&inter);
if (fe) {
- result = ve->qi();
+ result = fe->qi();
return 0;
}
result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index c663af0ccbb..370841327aa 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -916,7 +916,7 @@ void GPU_buffer_unlock(GPUBuffer *UNUSED(buffer), GPUBindingType binding)
{
int bindtypegl = gpu_binding_type_gl[binding];
/* note: this operation can fail, could return
- * an error code from this function? */
+ * an error code from this function? */
glUnmapBuffer(bindtypegl);
glBindBuffer(bindtypegl, 0);
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 3c028ff0805..aec94f9f2cb 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -853,11 +853,14 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_MTFACE) {
+ /* NOTE: For now we are using varying on purpose,
+ * otherwise we are not able to write to the varying.
+ */
BLI_dynstr_appendf(ds, "%s %s var%d%s;\n",
- GLEW_VERSION_3_0 ? "in" : "varying",
+ "varying",
GPU_DATATYPE_STR[input->type],
input->attribid,
- GLEW_VERSION_3_0 ? "[]" : "");
+ "");
BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n",
input->attribid);
}
@@ -868,22 +871,20 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl);
/* Generate varying assignments. */
- /* TODO(sergey): Disabled for now, needs revisit. */
-#if 0
for (node = nodes->first; node; node = node->next) {
for (input = node->inputs.first; input; input = input->next) {
if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
if (input->attribtype == CD_MTFACE) {
- BLI_dynstr_appendf(ds,
- "\tINTERP_FACE_VARYING_2(var%d, "
- "fvar%d_offset, st);\n",
- input->attribid,
- input->attribid);
+ BLI_dynstr_appendf(
+ ds,
+ "\tINTERP_FACE_VARYING_2(var%d, "
+ "int(texelFetch(FVarDataOffsetBuffer, fvar%d_offset).r), st);\n",
+ input->attribid,
+ input->attribid);
}
}
}
}
-#endif
BLI_dynstr_append(ds, "}\n");
code = BLI_dynstr_get_cstring(ds);
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 064e91743e8..7936811ab4d 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -803,7 +803,7 @@ static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int
* | | | |
* | NegZ | PosZ | PosY |
* |______|______|______|
- */
+ */
if (use_high_bit_depth) {
float (*frectb)[4] = (float(*)[4])frect;
float (**fsides)[4] = (float(**)[4])sides;
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index b8a39c81122..d41573b681b 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -77,9 +77,10 @@ static struct GPUGlobal {
GPUDeviceType device;
GPUOSType os;
GPUDriverType driver;
- float dfdyfactors[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
- calculate dfdy in shader differently when drawing to an offscreen buffer. First
- number is factor on screen and second is off-screen */
+ /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers
+ * calculate dfdy in shader differently when drawing to an offscreen buffer. First
+ * number is factor on screen and second is off-screen */
+ float dfdyfactors[2];
float max_anisotropy;
} GG = {1, 0};
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 0f95107c018..4775d2ed30a 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -1745,8 +1745,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr)
(GPU_link_changed(shi->refl) || ma->ref != 0.0f))
{
if (world->aocolor != WO_AOPLAIN) {
- if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr)))
- {
+ if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr))) {
GPUNodeLink *fcol, *f;
GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f);
GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f);
@@ -2887,8 +2886,7 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material,
"fvar%d_offset",
input->attribid);
location = GPU_shader_get_uniform(shader, name);
- /* Multiply by 2 because we're offseting U and V variables. */
- GPU_shader_uniform_int(shader, location, layer_index * 2);
+ GPU_shader_uniform_int(shader, location, layer_index);
}
}
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index 5a1b38e6be7..df1213b01e2 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -437,6 +437,10 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode,
/* TODO(sergey): Find a better place for this. */
if (use_opensubdiv && GLEW_VERSION_4_1) {
glProgramUniform1i(shader->program,
+ glGetUniformLocation(shader->program, "FVarDataOffsetBuffer"),
+ 30); /* GL_TEXTURE30 */
+
+ glProgramUniform1i(shader->program,
glGetUniformLocation(shader->program, "FVarDataBuffer"),
31); /* GL_TEXTURE31 */
}
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index 1663915549c..6f063883e37 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -32,6 +32,7 @@ uniform int osd_fvar_count;
}
uniform samplerBuffer FVarDataBuffer;
+uniform isamplerBuffer FVarDataOffsetBuffer;
out block {
VertexData v;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index f3bd817a7cc..845a78720ba 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1142,14 +1142,10 @@ void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
{
- float facm;
-
- fact *= facg;
- facm = 1.0 - fact;
+ vec4 col;
- vec3 one = vec3(1.0);
- vec3 scr = one - (one - texcol) * (one - outcol);
- incol = facm * outcol + fact * ((one - texcol) * outcol * texcol + outcol * scr);
+ mix_soft(fact * facg, vec4(outcol, 1.0), vec4(texcol, 1.0), col);
+ incol.rgb = col.rgb;
}
void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 26ced49a333..1987c6d2a9a 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -206,7 +206,7 @@ void imb_filterx(struct ImBuf *ibuf)
static void imb_filterN(ImBuf *out, ImBuf *in)
{
BLI_assert(out->channels == in->channels);
- BLI_assert(out->x == in->x && out->y == out->y);
+ BLI_assert(out->x == in->x && out->y == in->y);
const int channels = in->channels;
const int rowlen = in->x;
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index a55cef60943..a4418443790 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -117,7 +117,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp
to[0] = from[r][0];
to[1] = from[g][1];
to[2] = from[b][2];
- to[3] = MAX2(from[0][3], from[0][3]);
+ to[3] = MAX2(from[0][3], from[1][3]);
}
}
}
@@ -154,7 +154,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp
to[0] = from[r][0];
to[1] = from[g][1];
to[2] = from[b][2];
- to[3] = MAX2(from[0][3], from[0][3]);
+ to[3] = MAX2(from[0][3], from[1][3]);
}
}
}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index d7feb3a3880..0936284e354 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -354,7 +354,10 @@ typedef struct PreviewImage {
#define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0)
-#define ID_IS_LINKED_DATABLOCK(_id) (((ID *)(_id))->lib != NULL)
+#define ID_IS_LINKED(_id) (((ID *)(_id))->lib != NULL)
+#define LIB_IS_VIRTUAL(_lib) (((_lib)->flag & LIBRARY_FLAG_VIRTUAL) != 0)
+#define ID_IS_LINKED_DATABLOCK(_id) (ID_IS_LINKED(_id) && !LIB_IS_VIRTUAL(((ID *)(_id))->lib))
+#define ID_IS_LINKED_DATAPATH(_id) (ID_IS_LINKED(_id) && LIB_IS_VIRTUAL(((ID *)(_id))->lib))
#ifdef GS
# undef GS
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 3dca087c7fa..f4a1677efc4 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -4,7 +4,7 @@
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -70,7 +70,6 @@ typedef struct Brush {
float normal_weight;
float rake_factor; /* rake actual data (not texture), used for sculpt */
- int pad;
short blend; /* blend mode */
short ob_mode; /* & with ob->mode to see if the brush is compatible, use for display only. */
@@ -95,7 +94,6 @@ typedef struct Brush {
float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */
- int flag2;
int gradient_spacing;
int gradient_stroke_mode; /* source for stroke color gradient application */
int gradient_fill_mode; /* source for fill tool color gradient application */
@@ -104,7 +102,7 @@ typedef struct Brush {
char vertexpaint_tool; /* active vertex/weight paint blend mode (poorly named) */
char imagepaint_tool; /* active image paint tool */
char mask_tool; /* enum BrushMaskTool, only used if sculpt_tool is SCULPT_TOOL_MASK */
-
+
float autosmooth_factor;
float crease_pinch_factor;
@@ -333,5 +331,4 @@ typedef enum BlurKernelType {
#define MAX_BRUSH_PIXEL_RADIUS 500
-#endif
-
+#endif /* __DNA_BRUSH_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index 07bc2478837..d385e303a7c 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -42,7 +42,7 @@
*
* I've tried to keep similar, if not exact names for the variables as
* are presented in the paper. Where I've changed the concept slightly,
- * as in stepsPerFrame comapred to the time step in the paper, I've used
+ * as in stepsPerFrame compared to the time step in the paper, I've used
* variables with different names to minimize confusion.
*/
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index c9a5e056e4a..1d88b01cf62 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -157,10 +157,11 @@ typedef struct Scopes {
/* scopes->wavefrm_mode */
#define SCOPES_WAVEFRM_LUMA 0
-#define SCOPES_WAVEFRM_RGB 1
+#define SCOPES_WAVEFRM_RGB_PARADE 1
#define SCOPES_WAVEFRM_YCC_601 2
#define SCOPES_WAVEFRM_YCC_709 3
#define SCOPES_WAVEFRM_YCC_JPEG 4
+#define SCOPES_WAVEFRM_RGB 5
typedef struct ColorManagedViewSettings {
int flag, pad;
diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h
index bc127ac2c82..a2981c0aa76 100644
--- a/source/blender/makesdna/DNA_genfile.h
+++ b/source/blender/makesdna/DNA_genfile.h
@@ -69,8 +69,11 @@ typedef enum eSDNA_Type {
* For use with #DNA_struct_reconstruct & #DNA_struct_get_compareflags
*/
enum eSDNA_StructCompare {
+ /* Struct has disappeared (values of this struct type will not be loaded by the current Blender) */
SDNA_CMP_REMOVED = 0,
+ /* Struct is the same (can be loaded with straight memory copy after any necessary endian conversion) */
SDNA_CMP_EQUAL = 1,
+ /* Struct is different in some way (needs to be copied/converted field by field) */
SDNA_CMP_NOT_EQUAL = 2,
};
@@ -89,15 +92,15 @@ void DNA_sdna_current_free(void);
int DNA_struct_find_nr_ex(const struct SDNA *sdna, const char *str, unsigned int *index_last);
int DNA_struct_find_nr(const struct SDNA *sdna, const char *str);
void DNA_struct_switch_endian(const struct SDNA *oldsdna, int oldSDNAnr, char *data);
-char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA*newsdna);
+const char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA *newsdna);
void *DNA_struct_reconstruct(
const struct SDNA *newsdna, const struct SDNA *oldsdna,
- char *compflags, int oldSDNAnr, int blocks, void *data);
+ const char *compflags, int oldSDNAnr, int blocks, const void *data);
int DNA_elem_array_size(const char *str);
int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
-bool DNA_struct_elem_find(struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
+bool DNA_struct_elem_find(const struct SDNA *sdna, const char *stype, const char *vartype, const char *name);
int DNA_elem_type_size(const eSDNA_Type elem_nr);
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index a58e995f1c6..bbc8edf4344 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -641,8 +641,9 @@ typedef struct BooleanModifierData {
struct Object *object;
char operation;
- char bm_flag, pad[2];
- float threshold;
+ char solver;
+ char pad[2];
+ float double_threshold;
} BooleanModifierData;
typedef enum {
@@ -651,13 +652,10 @@ typedef enum {
eBooleanModifierOp_Difference = 2,
} BooleanModifierOp;
-/* temp bm_flag (debugging only) */
-enum {
- eBooleanModifierBMeshFlag_Enabled = (1 << 0),
- eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 1),
- eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 2),
- eBooleanModifierBMeshFlag_BMesh_NoConnectRegions = (1 << 3),
-};
+typedef enum {
+ eBooleanModifierSolver_Carve = 0,
+ eBooleanModifierSolver_BMesh = 1,
+} BooleanSolver;
typedef struct MDefInfluence {
int vertex;
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 58f4255068c..4c739203e77 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1273,7 +1273,9 @@ typedef struct CurvePaintSettings {
char flag;
char depth_mode;
char surface_plane;
- int error_threshold;
+ char fit_method;
+ char pad;
+ short error_threshold;
float radius_min, radius_max;
float radius_taper_start, radius_taper_end;
float surface_offset;
@@ -1288,6 +1290,12 @@ enum {
CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS = (1 << 3),
};
+/* CurvePaintSettings.fit_method */
+enum {
+ CURVE_PAINT_FIT_METHOD_REFIT = 0,
+ CURVE_PAINT_FIT_METHOD_SPLIT = 1,
+};
+
/* CurvePaintSettings.depth_mode */
enum {
CURVE_PAINT_PROJECT_CURSOR = 0,
diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h
index 26ea5cd4e93..bd8f23f30c1 100644
--- a/source/blender/makesdna/DNA_sdna_types.h
+++ b/source/blender/makesdna/DNA_sdna_types.h
@@ -45,7 +45,7 @@ typedef struct SDNA {
int pointerlen; /* size of a pointer in bytes */
int nr_types; /* number of basic types + struct types */
- char **types; /* type names */
+ const char **types; /* type names */
short *typelens; /* type lengths */
int nr_structs; /* number of struct types */
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 5b533d1ec48..4c243507e82 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -239,7 +239,7 @@ typedef struct View3D {
float stereo3d_convergence_alpha;
/* Previous viewport draw type.
- * Runtime-only, set in the rendered viewport otggle operator.
+ * Runtime-only, set in the rendered viewport toggle operator.
*/
short prev_drawtype;
short pad1;
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 0bb6e866bf4..8c758c33dc5 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -52,6 +52,8 @@ endif()
# SRC_DNA_INC is defined in the parent dir
+add_cc_flags_custom_test(makesdna)
+
add_executable(makesdna ${SRC} ${SRC_DNA_INC})
# Output dna.c
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index 1e3c91d5ddc..6a41591e051 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -134,39 +134,6 @@
*
*/
-/* ************************* ENDIAN STUFF ********************** */
-
-/**
- * converts a short between big/little endian.
- */
-static short le_short(short temp)
-{
- short new;
- char *rt = (char *)&temp, *rtn = (char *)&new;
-
- rtn[0] = rt[1];
- rtn[1] = rt[0];
-
- return new;
-}
-
-/**
- * converts an int between big/little endian.
- */
-static int le_int(int temp)
-{
- int new;
- char *rt = (char *)&temp, *rtn = (char *)&new;
-
- rtn[0] = rt[3];
- rtn[1] = rt[2];
- rtn[2] = rt[1];
- rtn[3] = rt[0];
-
- return new;
-}
-
-
/* ************************* MAKE DNA ********************** */
/* allowed duplicate code from makesdna.c */
@@ -338,6 +305,11 @@ int DNA_struct_find_nr(const SDNA *sdna, const char *str)
/* ************************* READ DNA ********************** */
+BLI_INLINE const char *pad_up_4(const char *ptr)
+{
+ return (const char *)((((uintptr_t)ptr) + 3) & ~3);
+}
+
/**
* In sdna->data the data, now we convert that to something understandable
*/
@@ -366,8 +338,7 @@ static bool init_structDNA(
return false;
}
else {
- intptr_t nr;
- char *cp;
+ const char *cp;
data++;
@@ -376,8 +347,10 @@ static bool init_structDNA(
if (*data == *verg) {
data++;
- if (do_endian_swap) sdna->nr_names = le_int(*data);
- else sdna->nr_names = *data;
+ sdna->nr_names = *data;
+ if (do_endian_swap) {
+ BLI_endian_switch_int32(&sdna->nr_names);
+ }
data++;
sdna->names = MEM_callocN(sizeof(void *) * sdna->nr_names, "sdnanames");
@@ -387,9 +360,8 @@ static bool init_structDNA(
return false;
}
- nr = 0;
cp = (char *)data;
- while (nr < sdna->nr_names) {
+ for (int nr = 0; nr < sdna->nr_names; nr++) {
sdna->names[nr] = cp;
/* "float gravity [3]" was parsed wrong giving both "gravity" and
@@ -404,20 +376,20 @@ static bool init_structDNA(
while (*cp) cp++;
cp++;
- nr++;
}
- nr = (intptr_t)cp; /* prevent BUS error */
- nr = (nr + 3) & ~3;
- cp = (char *)nr;
+
+ cp = pad_up_4(cp);
/* load type names array */
data = (int *)cp;
strcpy(str, "TYPE");
if (*data == *verg) {
data++;
-
- if (do_endian_swap) sdna->nr_types = le_int(*data);
- else sdna->nr_types = *data;
+
+ sdna->nr_types = *data;
+ if (do_endian_swap) {
+ BLI_endian_switch_int32(&sdna->nr_types);
+ }
data++;
sdna->types = MEM_callocN(sizeof(void *) * sdna->nr_types, "sdnatypes");
@@ -427,9 +399,8 @@ static bool init_structDNA(
return false;
}
- nr = 0;
cp = (char *)data;
- while (nr < sdna->nr_types) {
+ for (int nr = 0; nr < sdna->nr_types; nr++) {
sdna->types[nr] = cp;
/* this is a patch, to change struct names without a conflict with SDNA */
@@ -442,11 +413,9 @@ static bool init_structDNA(
while (*cp) cp++;
cp++;
- nr++;
}
- nr = (intptr_t)cp; /* prevent BUS error */
- nr = (nr + 3) & ~3;
- cp = (char *)nr;
+
+ cp = pad_up_4(cp);
/* load typelen array */
data = (int *)cp;
@@ -457,13 +426,7 @@ static bool init_structDNA(
sdna->typelens = sp;
if (do_endian_swap) {
- short a, *spo = sp;
-
- a = sdna->nr_types;
- while (a--) {
- spo[0] = le_short(spo[0]);
- spo++;
- }
+ BLI_endian_switch_int16_array(sp, sdna->nr_types);
}
sp += sdna->nr_types;
@@ -480,8 +443,10 @@ static bool init_structDNA(
if (*data == *verg) {
data++;
- if (do_endian_swap) sdna->nr_structs = le_int(*data);
- else sdna->nr_structs = *data;
+ sdna->nr_structs = *data;
+ if (do_endian_swap) {
+ BLI_endian_switch_int32(&sdna->nr_structs);
+ }
data++;
sdna->structs = MEM_callocN(sizeof(void *) * sdna->nr_structs, "sdnastrcs");
@@ -491,37 +456,34 @@ static bool init_structDNA(
return false;
}
- nr = 0;
sp = (short *)data;
- while (nr < sdna->nr_structs) {
+ for (int nr = 0; nr < sdna->nr_structs; nr++) {
sdna->structs[nr] = sp;
if (do_endian_swap) {
short a;
- sp[0] = le_short(sp[0]);
- sp[1] = le_short(sp[1]);
+ BLI_endian_switch_int16(&sp[0]);
+ BLI_endian_switch_int16(&sp[1]);
a = sp[1];
sp += 2;
while (a--) {
- sp[0] = le_short(sp[0]);
- sp[1] = le_short(sp[1]);
+ BLI_endian_switch_int16(&sp[0]);
+ BLI_endian_switch_int16(&sp[1]);
sp += 2;
}
}
else {
sp += 2 * sp[1] + 2;
}
-
- nr++;
}
}
{
/* second part of gravity problem, setting "gravity" type to void */
if (gravity_fix > -1) {
- for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) {
+ for (int nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
if (strcmp(sdna->types[sp[0]], "ClothSimSettings") == 0)
sp[10] = SDNA_TYPE_VOID;
@@ -536,7 +498,7 @@ static bool init_structDNA(
for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) {
sp = sdna->structs[nr];
- BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr));
+ BLI_ghash_insert(sdna->structs_map, (void *)sdna->types[sp[0]], SET_INT_IN_POINTER(nr));
}
}
#endif
@@ -670,13 +632,8 @@ static void recurs_test_compflags(const SDNA *sdna, char *compflags, int structn
/**
* Constructs and returns an array of byte flags with one element for each struct in oldsdna,
* indicating how it compares to newsdna:
- *
- * flag value:
- * - 0 Struct has disappeared (values of this struct type will not be loaded by the current Blender)
- * - 1 Struct is the same (can be loaded with straight memory copy after any necessary endian conversion)
- * - 2 Struct is different in some way (needs to be copied/converted field by field)
*/
-char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna)
+const char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna)
{
int a, b;
const short *sp_old, *sp_new;
@@ -947,12 +904,12 @@ static int elem_strcmp(const char *name, const char *oname)
* \param sppo Optional place to return pointer to field info in sdna
* \return Data address.
*/
-static char *find_elem(
+static const char *find_elem(
const SDNA *sdna,
const char *type,
const char *name,
const short *old,
- char *olddata,
+ const char *olddata,
const short **sppo)
{
int a, elemcount, len;
@@ -1100,7 +1057,7 @@ static void reconstruct_struct(
const char *compflags,
int oldSDNAnr,
- char *data,
+ const char *data,
int curSDNAnr,
char *cur)
{
@@ -1111,7 +1068,8 @@ static void reconstruct_struct(
int a, elemcount, elen, eleno, mul, mulo, firststructtypenr;
const short *spo, *spc, *sppo;
const char *type;
- char *cpo, *cpc;
+ const char *cpo;
+ char *cpc;
const char *name, *nameo;
unsigned int oldsdna_index_last = UINT_MAX;
@@ -1149,7 +1107,7 @@ static void reconstruct_struct(
if (spc[0] >= firststructtypenr && !ispointer(name)) {
/* struct field type */
/* where does the old struct data start (and is there an old one?) */
- cpo = find_elem(oldsdna, type, name, spo, data, &sppo);
+ cpo = (char *)find_elem(oldsdna, type, name, spo, data, &sppo);
if (cpo) {
oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last);
@@ -1226,7 +1184,7 @@ void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data)
if (spc[0] >= firststructtypenr && !ispointer(name)) {
/* struct field type */
/* where does the old data start (is there one?) */
- char *cpo = find_elem(oldsdna, type, name, spo, data, NULL);
+ char *cpo = (char *)find_elem(oldsdna, type, name, spo, data, NULL);
if (cpo) {
oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last);
@@ -1288,11 +1246,12 @@ void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data)
*/
void *DNA_struct_reconstruct(
const SDNA *newsdna, const SDNA *oldsdna,
- char *compflags, int oldSDNAnr, int blocks, void *data)
+ const char *compflags, int oldSDNAnr, int blocks, const void *data)
{
int a, curSDNAnr, curlen = 0, oldlen;
const short *spo, *spc;
- char *cur, *cpc, *cpo;
+ char *cur, *cpc;
+ const char *cpo;
const char *type;
/* oldSDNAnr == structnr, we're looking for the corresponding 'cur' number */
@@ -1335,7 +1294,7 @@ int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const ch
return (int)((intptr_t)cp);
}
-bool DNA_struct_elem_find(SDNA *sdna, const char *stype, const char *vartype, const char *name)
+bool DNA_struct_elem_find(const SDNA *sdna, const char *stype, const char *vartype, const char *name)
{
const int SDNAnr = DNA_struct_find_nr(sdna, stype);
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index b1048f72022..7ae3d552916 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -52,6 +52,7 @@ extern EnumPropertyItem rna_enum_proportional_editing_items[];
extern EnumPropertyItem rna_enum_snap_target_items[];
extern EnumPropertyItem rna_enum_snap_element_items[];
extern EnumPropertyItem rna_enum_snap_node_element_items[];
+extern EnumPropertyItem rna_enum_curve_fit_method_items[];
extern EnumPropertyItem rna_enum_mesh_select_mode_items[];
extern EnumPropertyItem rna_enum_mesh_delimit_mode_items[];
extern EnumPropertyItem rna_enum_space_type_items[];
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 17b65a9d529..01db7b338b9 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -351,7 +351,10 @@ blender_include_dirs_sys(
"${GLEW_INCLUDE_PATH}"
)
+add_cc_flags_custom_test(makesrna)
+
add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC})
+
target_link_libraries(makesrna bf_dna)
target_link_libraries(makesrna bf_dna_blenlib)
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 813c1062a02..8af9fa87865 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3299,7 +3299,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_animviz.c", NULL, RNA_def_animviz},
{"rna_actuator.c", "rna_actuator_api.c", RNA_def_actuator},
{"rna_armature.c", "rna_armature_api.c", RNA_def_armature},
- {"rna_asset.c", NULL, RNA_def_asset},
+ {"rna_asset.c", NULL, RNA_def_asset},
{"rna_boid.c", NULL, RNA_def_boid},
{"rna_brush.c", NULL, RNA_def_brush},
{"rna_camera.c", "rna_camera_api.c", RNA_def_camera},
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 533b1991ba5..528aabf33ee 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -698,7 +698,7 @@ static void rna_ImagePreview_icon_pixels_float_set(PointerRNA *ptr, const float
static int rna_ImagePreview_icon_id_get(PointerRNA *ptr)
{
/* Using a callback here allows us to only generate icon matching that preview when icon_id is requested. */
- return BKE_icon_preview_ensure((PreviewImage *)(ptr->data));
+ return BKE_icon_preview_ensure(ptr->id.data, (PreviewImage *)(ptr->data));
}
static void rna_ImagePreview_icon_reload(PreviewImage *prv)
{
@@ -1061,6 +1061,7 @@ static void rna_def_ID(BlenderRNA *brna)
static void rna_def_library(BlenderRNA *brna)
{
StructRNA *srna;
+ FunctionRNA *func;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "Library", "ID");
@@ -1079,6 +1080,10 @@ static void rna_def_library(BlenderRNA *brna)
prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "packedfile");
RNA_def_property_ui_text(prop, "Packed File", "");
+
+ func = RNA_def_function(srna, "reload", "WM_lib_reload");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Reload this library and all its linked datablocks");
}
void RNA_def_ID(BlenderRNA *brna)
{
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 00b7df122ee..5a93e18a7dd 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -3127,8 +3127,11 @@ void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA
RNA_parameter_list_free(&params);
}
}
- /*else
- printf("%s %s.%s: not implemented for this property.\n", __func__, ptr->type->identifier, prop->identifier);*/
+#if 0
+ else {
+ printf("%s %s.%s: not implemented for this property.\n", __func__, ptr->type->identifier, prop->identifier);
+ }
+#endif
#endif
if (r_ptr) {
@@ -3187,8 +3190,11 @@ bool RNA_property_collection_remove(PointerRNA *ptr, PropertyRNA *prop, int key)
return false;
}
- /*else
- printf("%s %s.%s: only supported for id properties.\n", __func__, ptr->type->identifier, prop->identifier);*/
+#if 0
+ else {
+ printf("%s %s.%s: only supported for id properties.\n", __func__, ptr->type->identifier, prop->identifier);
+ }
+#endif
#endif
return false;
}
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index c3d1070b8c2..7a1954036e3 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -116,6 +116,23 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value)
}
}
+static void rna_AnimData_tweakmode_set(PointerRNA *ptr, const int value)
+{
+ AnimData *adt = (AnimData *)ptr->data;
+
+ /* NOTE: technically we should also set/unset SCE_NLA_EDIT_ON flag on the
+ * scene which is used to make polling tests faster, but this flag is weak
+ * and can easily break e.g. by changing layer visibility. This needs to be
+ * dealt with at some point. */
+
+ if (value) {
+ BKE_nla_tweakmode_enter(adt);
+ }
+ else {
+ BKE_nla_tweakmode_exit(adt);
+ }
+}
+
/* ****************************** */
/* wrapper for poll callback */
@@ -1041,6 +1058,12 @@ static void rna_def_animdata(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADT_NLA_EVAL_OFF);
RNA_def_property_ui_text(prop, "NLA Evaluation Enabled", "NLA stack is evaluated when evaluating this block");
RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
+
+ prop = RNA_def_property(srna, "use_tweak_mode", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ADT_NLA_EDIT_ON);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_AnimData_tweakmode_set");
+ RNA_def_property_ui_text(prop, "Use NLA Tweak Mode", "Whether to enable or disable tweak mode in NLA");
+ RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL);
}
/* --- */
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 842e220e8b5..5c7f51516cb 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -498,13 +498,13 @@ void rna_def_bone_curved_common(StructRNA *srna, bool is_posebone)
/* Roll In/Out */
prop = RNA_def_property(srna, "bbone_rollin", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "roll1");
- RNA_def_property_range(prop, -M_PI * 2.0f, M_PI * 2.0f);
+ RNA_def_property_range(prop, -M_PI * 2.0, M_PI * 2.0);
RNA_def_property_ui_text(prop, "Roll In", "Roll offset for the start of the B-Bone, adjusts twist");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
prop = RNA_def_property(srna, "bbone_rollout", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "roll2");
- RNA_def_property_range(prop, -M_PI * 2.0f, M_PI * 2.0f);
+ RNA_def_property_range(prop, -M_PI * 2.0, M_PI * 2.0);
RNA_def_property_ui_text(prop, "Roll Out", "Roll offset for the end of the B-Bone, adjusts twist");
RNA_DEF_CURVEBONE_UPDATE(prop, is_posebone);
diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c
index 0d1279e96df..afd23e9fa0d 100644
--- a/source/blender/makesrna/intern/rna_asset.c
+++ b/source/blender/makesrna/intern/rna_asset.c
@@ -35,7 +35,7 @@
#include "rna_internal.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_idprop.h"
#include "WM_types.h"
@@ -46,7 +46,6 @@
#include "RNA_access.h"
-#include "BKE_asset.h"
#include "BKE_context.h"
#include "BKE_report.h"
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 492430fbda6..078ba13d76d 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -159,13 +159,13 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "pole_merge_angle_from", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_range(prop, 0.0f, M_PI / 2.0f);
+ RNA_def_property_range(prop, 0.0f, M_PI / 2.0);
RNA_def_property_ui_text(prop, "Pole Merge Start Angle",
"Angle at which interocular distance starts to fade to 0");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
prop = RNA_def_property(srna, "pole_merge_angle_to", PROP_FLOAT, PROP_ANGLE);
- RNA_def_property_range(prop, 0.0f, M_PI / 2.0f);
+ RNA_def_property_range(prop, 0.0f, M_PI / 2.0);
RNA_def_property_ui_text(prop, "Pole Merge End Angle",
"Angle at which interocular distance is 0");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 021bc608564..78e3bbe4176 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -1018,10 +1018,11 @@ static void rna_def_scopes(BlenderRNA *brna)
static EnumPropertyItem prop_wavefrm_mode_items[] = {
{SCOPES_WAVEFRM_LUMA, "LUMA", ICON_COLOR, "Luma", ""},
- {SCOPES_WAVEFRM_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""},
+ {SCOPES_WAVEFRM_RGB_PARADE, "PARADE", ICON_COLOR, "Parade", ""},
{SCOPES_WAVEFRM_YCC_601, "YCBCR601", ICON_COLOR, "YCbCr (ITU 601)", ""},
{SCOPES_WAVEFRM_YCC_709, "YCBCR709", ICON_COLOR, "YCbCr (ITU 709)", ""},
{SCOPES_WAVEFRM_YCC_JPEG, "YCBCRJPG", ICON_COLOR, "YCbCr (Jpeg)", ""},
+ {SCOPES_WAVEFRM_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 16e0f17eac5..091950a8e66 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -204,18 +204,6 @@ static char *rna_FluidSettings_path(PointerRNA *ptr)
return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc);
}
-static void rna_FluidMeshVertex_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
- rna_iterator_array_begin(iter, fss->meshVelocities, sizeof(float) * 3, fss->totvert, 0, NULL);
-}
-
-static int rna_FluidMeshVertex_data_length(PointerRNA *ptr)
-{
- FluidsimSettings *fss = (FluidsimSettings *)ptr->data;
- return fss->totvert;
-}
-
#else
static void rna_def_fluidsim_slip(StructRNA *srna)
@@ -251,9 +239,8 @@ static void rna_def_fluid_mesh_vertices(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- srna = RNA_def_struct(brna, "FluidMeshVertex", NULL);
- RNA_def_struct_sdna(srna, "FluidVertexVelocity");
- RNA_def_struct_ui_text(srna, "Fluid Mesh Vertex", "Vertex of a simulated fluid mesh");
+ srna = RNA_def_struct(brna, "FluidVertexVelocity", NULL);
+ RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh");
RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL);
prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY);
@@ -442,11 +429,10 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna)
/* simulated fluid mesh data */
prop = RNA_def_property(srna, "fluid_mesh_vertices", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "FluidMeshVertex");
+ RNA_def_property_collection_sdna(prop, NULL, "meshVelocities", "totvert");
+ RNA_def_property_struct_type(prop, "FluidVertexVelocity");
RNA_def_property_ui_text(prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation");
- RNA_def_property_collection_funcs(prop, "rna_FluidMeshVertex_data_begin", "rna_iterator_array_next",
- "rna_iterator_array_end", "rna_iterator_array_get",
- "rna_FluidMeshVertex_data_length", NULL, NULL, NULL);
+
rna_def_fluid_mesh_vertices(brna);
}
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index ef74f01f9be..a23ef6eaa82 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1895,6 +1895,12 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_solver_items[] = {
+ {eBooleanModifierSolver_BMesh, "BMESH", 0, "BMesh", "Use the BMesh boolean solver"},
+ {eBooleanModifierSolver_Carve, "CARVE", 0, "Carve", "Use the Carve boolean solver"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "BooleanModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Boolean Modifier", "Boolean operations modifier");
RNA_def_struct_sdna(srna, "BooleanModifierData");
@@ -1911,35 +1917,17 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Operation", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
-#if 0 /* WITH_MOD_BOOLEAN */
- /* BMesh intersection options */
- prop = RNA_def_property(srna, "use_bmesh", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_Enabled);
- RNA_def_property_ui_text(prop, "Use BMesh", "Use BMesh boolean calculation");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "use_bmesh_separate", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_Separate);
- RNA_def_property_ui_text(prop, "Separate", "Keep edges separate");
+ prop = RNA_def_property(srna, "solver", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_solver_items);
+ RNA_def_property_ui_text(prop, "Solver", "");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_property(srna, "use_bmesh_dissolve", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoDissolve);
- RNA_def_property_ui_text(prop, "Dissolve", "Dissolve verts created from tessellated intersection");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "use_bmesh_connect_regions", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoConnectRegions);
- RNA_def_property_ui_text(prop, "Calculate Holes", "Connect regions (needed for hole filling)");
- RNA_def_property_update(prop, 0, "rna_Modifier_update");
-
- prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_DISTANCE);
- RNA_def_property_float_sdna(prop, NULL, "threshold");
+ prop = RNA_def_property(srna, "double_threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "double_threshold");
RNA_def_property_range(prop, 0, 1.0f);
- RNA_def_property_ui_range(prop, 0, 1, 1, 7);
- RNA_def_property_ui_text(prop, "Threshold", "");
+ RNA_def_property_ui_range(prop, 0, 1, 0.0001, 7);
+ RNA_def_property_ui_text(prop, "Overlap Threshold", "Threshold for checking overlapping geometry");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
-#endif
}
static void rna_def_modifier_array(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index f15625259a9..9683495c54c 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -1033,7 +1033,7 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value)
ob->gameflag &= ~(OB_SENSOR | OB_OCCLUDER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR |
OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH);
/* When we switch to character physics and the collision bounds is set to triangle mesh
- we have to change collision bounds because triangle mesh is not supported by Characters*/
+ * we have to change collision bounds because triangle mesh is not supported by Characters */
if ((ob->gameflag & OB_BOUNDS) && ob->collision_boundtype == OB_BOUND_TRIANGLE_MESH) {
ob->boundtype = ob->collision_boundtype = OB_BOUND_BOX;
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d1f8c4e5bed..ed90f146f4d 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -178,6 +178,11 @@ EnumPropertyItem snap_uv_element_items[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem rna_enum_curve_fit_method_items[] = {
+ {CURVE_PAINT_FIT_METHOD_REFIT, "REFIT", 0, "Refit", "Incrementally re-fit the curve (high quality)"},
+ {CURVE_PAINT_FIT_METHOD_SPLIT, "SPLIT", 0, "Split", "Split the curve until the tolerance is met (fast)"},
+ {0, NULL, 0, NULL, NULL}};
+
/* workaround for duplicate enums,
* have each enum line as a define then conditionally set it or not
*/
@@ -2638,6 +2643,11 @@ static void rna_def_curve_paint_settings(BlenderRNA *brna)
RNA_def_property_range(prop, 1, 100);
RNA_def_property_ui_text(prop, "Tolerance", "Allow deviation for a smoother, less precise line");
+ prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_PIXEL);
+ RNA_def_property_enum_sdna(prop, NULL, "fit_method");
+ RNA_def_property_enum_items(prop, rna_enum_curve_fit_method_items);
+ RNA_def_property_ui_text(prop, "Method", "Curve fitting method");
+
prop = RNA_def_property(srna, "corner_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, 0, M_PI);
RNA_def_property_ui_text(prop, "Corner Angle", "Angles above this are considered corners");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 738554af9c0..4437c26f0be 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -35,7 +35,7 @@
#include "RNA_define.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_movieclip.h"
@@ -253,7 +253,7 @@ EnumPropertyItem rna_enum_file_sort_items[] = {
#include "BLI_math.h"
#include "BKE_animsys.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -3661,7 +3661,7 @@ static void rna_def_space_nla(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_local_markers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOLOCALMARKERS);
RNA_def_property_ui_text(prop, "Show Local Markers",
- "Show action-local markers on the strips, useful when synchronising timing across strips");
+ "Show action-local markers on the strips, useful when synchronizing timing across strips");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL);
/* editing */
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 3f418fa16f3..da0f5aa3923 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -33,7 +33,7 @@
*/
// #ifdef DEBUG_TIME
-// #define USE_BMESH
+#define USE_BMESH
#ifdef WITH_MOD_BOOLEAN
# define USE_CARVE WITH_MOD_BOOLEAN
#endif
@@ -71,6 +71,14 @@
#include "PIL_time_utildefines.h"
#endif
+static void initData(ModifierData *md)
+{
+ BooleanModifierData *bmd = (BooleanModifierData *)md;
+
+ bmd->solver = eBooleanModifierSolver_BMesh;
+ bmd->double_threshold = 1e-6f;
+}
+
static void copyData(ModifierData *md, ModifierData *target)
{
#if 0
@@ -222,7 +230,9 @@ static DerivedMesh *applyModifier_bmesh(
#ifdef DEBUG_TIME
TIMEIT_START(boolean_bmesh);
#endif
- bm = BM_mesh_create_ex(&allocsize, );
+ bm = BM_mesh_create(
+ &allocsize,
+ &((struct BMeshCreateParams){.use_toolflags = false,}));
DM_to_bmesh_ex(dm_other, bm, true);
DM_to_bmesh_ex(dm, bm, true);
@@ -296,16 +306,21 @@ static DerivedMesh *applyModifier_bmesh(
* currently this is ok for 'BM_mesh_intersect' */
// BM_mesh_normals_update(bm);
+ /* change for testing */
+ bool use_separate = false;
+ bool use_dissolve = true;
+ bool use_island_connect = true;
+
BM_mesh_intersect(
bm,
looptris, tottri,
bm_face_isect_pair, NULL,
false,
- (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0,
- (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0,
- (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0,
+ use_separate,
+ use_dissolve,
+ use_island_connect,
bmd->operation,
- bmd->threshold);
+ bmd->double_threshold);
MEM_freeN(looptris);
}
@@ -409,15 +424,14 @@ static DerivedMesh *applyModifier(
ModifierApplyFlag flag)
{
BooleanModifierData *bmd = (BooleanModifierData *)md;
- const int method = (bmd->bm_flag & eBooleanModifierBMeshFlag_Enabled) ? 1 : 0;
- switch (method) {
+ switch (bmd->solver) {
#ifdef USE_CARVE
- case 0:
+ case eBooleanModifierSolver_Carve:
return applyModifier_carve(md, ob, derivedData, flag);
#endif
#ifdef USE_BMESH
- case 1:
+ case eBooleanModifierSolver_BMesh:
return applyModifier_bmesh(md, ob, derivedData, flag);
#endif
default:
@@ -441,7 +455,7 @@ ModifierTypeInfo modifierType_Boolean = {
/* deformMatricesEM */ NULL,
/* applyModifier */ applyModifier,
/* applyModifierEM */ NULL,
- /* initData */ NULL,
+ /* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ isDisabled,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 2cfa746ab3c..ceb7dc02699 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -144,8 +144,9 @@ static void mix_normals(
break;
}
- interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new,
- (mix_limit < M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac);
+ interp_v3_v3v3_slerp_safe(
+ *no_new, *no_old, *no_new,
+ (mix_limit < (float)M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac);
}
MEM_SAFE_FREE(facs);
@@ -390,7 +391,7 @@ static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *o
const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
(smd->mix_factor == 1.0f) &&
(smd->defgrp_name[0] == '\0') &&
- (smd->mix_limit == M_PI));
+ (smd->mix_limit == (float)M_PI));
int defgrp_index;
MDeformVert *dvert;
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index eb1594688c7..d5973baeadb 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -207,20 +207,21 @@ PyObject *BPyInit_bmesh(void)
/* bmesh.types */
PyModule_AddObject(mod, "types", (submodule = BPyInit_bmesh_types()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
+ /* bmesh.ops (not a real module, exposes module like access). */
PyModule_AddObject(mod, "ops", (submodule = BPyInit_bmesh_ops()));
- /* PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); */
+ /* PyDict_SetItemString(sys_modules, PyModule_GetNameObject(submodule), submodule); */
PyDict_SetItemString(sys_modules, "bmesh.ops", submodule); /* fake module */
Py_INCREF(submodule);
PyModule_AddObject(mod, "utils", (submodule = BPyInit_bmesh_utils()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
PyModule_AddObject(mod, "geometry", (submodule = BPyInit_bmesh_geometry()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
return mod;
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index db8ed072722..11646f3f3df 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -1560,7 +1560,7 @@ PyObject *BPyInit_idprop(void)
/* idprop.types */
PyModule_AddObject(mod, "types", (submodule = BPyInit_idprop_types()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
return mod;
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 7f13a7a4d94..72dec55e50b 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -177,7 +177,7 @@ PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type,
/**
* Caller needs to ensure tuple is uninitialized.
- * Handy for filling a typle with None for eg.
+ * Handy for filling a tuple with None for eg.
*/
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value)
{
@@ -367,11 +367,12 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings)
}
-/* similar to PyErr_Format(),
+/**
+ * Similar to #PyErr_Format(),
*
- * implementation - we cant actually preprend the existing exception,
+ * Implementation - we cant actually prepend the existing exception,
* because it could have _any_ arguments given to it, so instead we get its
- * __str__ output and raise our own exception including it.
+ * ``__str__`` output and raise our own exception including it.
*/
PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...)
{
@@ -748,6 +749,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...)
/* set the value so we can access it */
PyDict_SetItemString(py_dict, "values", values);
+ Py_DECREF(values);
py_result = PyRun_File(fp, filepath, Py_file_input, py_dict, py_dict);
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 9f83bc94760..538ff7ba257 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -236,7 +236,7 @@ static int bpy_app_debug_set(PyObject *UNUSED(self), PyObject *value, void *clos
PyDoc_STRVAR(bpy_app_binary_path_python_doc,
"String, the path to the python executable (read-only)"
);
-static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UNUSED(closure))
+static PyObject *bpy_app_binary_path_python_get(PyObject *self, void *UNUSED(closure))
{
/* refcount is held in BlenderAppType.tp_dict */
static PyObject *ret = NULL;
@@ -248,7 +248,7 @@ static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UN
fullpath, sizeof(fullpath),
PY_MAJOR_VERSION, PY_MINOR_VERSION);
ret = PyC_UnicodeFromByte(fullpath);
- PyDict_SetItemString(BlenderAppType.tp_dict, "binary_path_python", ret);
+ PyDict_SetItem(BlenderAppType.tp_dict, PyDescr_NAME(self), ret);
}
else {
Py_INCREF(ret);
@@ -363,10 +363,10 @@ static PyGetSetDef bpy_app_getsets[] = {
static void py_struct_seq_getset_init(void)
{
/* tricky dynamic members, not to py-spec! */
- PyGetSetDef *getset;
-
- for (getset = bpy_app_getsets; getset->name; getset++) {
- PyDict_SetItemString(BlenderAppType.tp_dict, getset->name, PyDescr_NewGetSet(&BlenderAppType, getset));
+ for (PyGetSetDef *getset = bpy_app_getsets; getset->name; getset++) {
+ PyObject *item = PyDescr_NewGetSet(&BlenderAppType, getset);
+ PyDict_SetItem(BlenderAppType.tp_dict, PyDescr_NAME(item), item);
+ Py_DECREF(item);
}
}
/* end dynamic bpy.app */
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index 9b477e384db..65b6bd501ce 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -110,9 +110,11 @@ static void bpy_pydriver_update_dict(const float evaltime)
bpy_pydriver_InternStr__frame = PyUnicode_FromString("frame");
}
+ PyObject *item = PyFloat_FromDouble(evaltime);
PyDict_SetItem(bpy_pydriver_Dict,
bpy_pydriver_InternStr__frame,
- PyFloat_FromDouble(evaltime));
+ item);
+ Py_DECREF(item);
bpy_pydriver_evaltime_prev = evaltime;
}
@@ -301,7 +303,10 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime)
/* try to add to dictionary */
/* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */
- if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) < 0) {
+ if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) != -1) {
+ Py_DECREF(driver_arg);
+ }
+ else {
/* this target failed - bad name */
if (targets_ok) {
/* first one - print some extra info for easier identification */
diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c
index a120e4886e0..37a7e0e23dd 100644
--- a/source/blender/python/intern/bpy_library_load.c
+++ b/source/blender/python/intern/bpy_library_load.c
@@ -39,7 +39,6 @@
#include "BLO_readfile.h"
-#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_library.h"
#include "BKE_idcode.h"
@@ -186,6 +185,7 @@ PyDoc_STRVAR(bpy_lib_load_doc,
static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
static const char *kwlist[] = {"filepath", "link", "relative", NULL};
+ Main *bmain = CTX_data_main(BPy_GetContext());
BPy_Library *ret;
const char *filename = NULL;
bool is_rel = false, is_link = false;
@@ -204,7 +204,7 @@ static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *
BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath));
BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath));
- BLI_path_abs(ret->abspath, G.main->name);
+ BLI_path_abs(ret->abspath, bmain->name);
ret->blo_handle = NULL;
ret->flag = ((is_link ? FILE_LINK : 0) |
@@ -222,19 +222,16 @@ static PyObject *_bpy_names(BPy_Library *self, int blocktype)
int totnames;
names = BLO_blendhandle_get_datablock_names(self->blo_handle, blocktype, &totnames);
+ list = PyList_New(totnames);
if (names) {
int counter = 0;
- list = PyList_New(totnames);
for (l = names; l; l = l->next) {
PyList_SET_ITEM(list, counter, PyUnicode_FromString((char *)l->link));
counter++;
}
BLI_linklist_free(names, free); /* free linklist *and* each node's data */
}
- else {
- list = PyList_New(0);
- }
return list;
}
@@ -264,8 +261,13 @@ static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args))
if (BKE_idcode_is_linkable(code)) {
const char *name_plural = BKE_idcode_to_name_plural(code);
PyObject *str = PyUnicode_FromString(name_plural);
- PyDict_SetItem(self->dict, str, PyList_New(0));
- PyDict_SetItem(from_dict, str, _bpy_names(self, code));
+ PyObject *item;
+
+ PyDict_SetItem(self->dict, str, item = PyList_New(0));
+ Py_DECREF(item);
+ PyDict_SetItem(from_dict, str, item = _bpy_names(self, code));
+ Py_DECREF(item);
+
Py_DECREF(str);
}
}
@@ -346,48 +348,44 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
/* loop */
Py_ssize_t size = PyList_GET_SIZE(ls);
Py_ssize_t i;
- PyObject *item;
- const char *item_str;
for (i = 0; i < size; i++) {
- item = PyList_GET_ITEM(ls, i);
- item_str = _PyUnicode_AsString(item);
+ PyObject *item_src = PyList_GET_ITEM(ls, i);
+ PyObject *item_dst; /* must be set below */
+ const char *item_idname = _PyUnicode_AsString(item_src);
- // printf(" %s\n", item_str);
+ // printf(" %s\n", item_idname);
- if (item_str) {
- ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_str);
+ if (item_idname) {
+ ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_idname);
if (id) {
#ifdef USE_RNA_DATABLOCKS
/* swap name for pointer to the id */
- Py_DECREF(item);
- item = PyCapsule_New((void *)id, NULL, NULL);
+ item_dst = PyCapsule_New((void *)id, NULL, NULL);
+#else
+ /* leave as is */
+ continue;
#endif
}
else {
- bpy_lib_exit_warn_idname(self, name_plural, item_str);
+ bpy_lib_exit_warn_idname(self, name_plural, item_idname);
/* just warn for now */
/* err = -1; */
-#ifdef USE_RNA_DATABLOCKS
- item = Py_INCREF_RET(Py_None);
-#endif
+ item_dst = Py_INCREF_RET(Py_None);
}
/* ID or None */
}
else {
/* XXX, could complain about this */
- bpy_lib_exit_warn_type(self, item);
+ bpy_lib_exit_warn_type(self, item_src);
PyErr_Clear();
-
-#ifdef USE_RNA_DATABLOCKS
- item = Py_INCREF_RET(Py_None);
-#endif
+ item_dst = Py_INCREF_RET(Py_None);
}
-#ifdef USE_RNA_DATABLOCKS
- PyList_SET_ITEM(ls, i, item);
-#endif
+ /* item_dst must be new or already incref'd */
+ Py_DECREF(item_src);
+ PyList_SET_ITEM(ls, i, item_dst);
}
}
}
@@ -410,7 +408,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
/* copied from wm_operator.c */
{
/* mark all library linked objects to be updated */
- BKE_main_lib_objects_recalc_all(G.main);
+ BKE_main_lib_objects_recalc_all(bmain);
/* append, rather than linking */
if ((self->flag & FILE_LINK) == 0) {
@@ -422,6 +420,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
/* finally swap the capsules for real bpy objects
* important since BLO_library_append_end initializes NodeTree types used by srna->refine */
+#ifdef USE_RNA_DATABLOCKS
{
int idcode_step = 0, idcode;
while ((idcode = BKE_idcode_iter_step(&idcode_step))) {
@@ -451,6 +450,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args))
}
}
}
+#endif /* USE_RNA_DATABLOCKS */
Py_RETURN_NONE;
}
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index eaa96e6243c..bd3e5736c6c 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -223,9 +223,9 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
WM_operator_properties_create_ptr(&ptr, ot);
WM_operator_properties_sanitize(&ptr, 0);
- if (kw && PyDict_Size(kw))
- error_val = pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: ");
-
+ if (kw && PyDict_Size(kw)) {
+ error_val = pyrna_pydict_to_props(&ptr, kw, false, "Converting py args to operator properties: ");
+ }
if (error_val == 0) {
ReportList *reports;
@@ -353,8 +353,9 @@ static PyObject *pyop_as_string(PyObject *UNUSED(self), PyObject *args)
/* Save another lookup */
RNA_pointer_create(NULL, ot->srna, NULL, &ptr);
- if (kw && PyDict_Size(kw))
- error_val = pyrna_pydict_to_props(&ptr, kw, 0, "Converting py args to operator properties: ");
+ if (kw && PyDict_Size(kw)) {
+ error_val = pyrna_pydict_to_props(&ptr, kw, false, "Converting py args to operator properties: ");
+ }
if (error_val == 0)
buf = WM_operator_pystring_ex(C, NULL, all_args, macro_args, ot, &ptr);
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index bce1d923462..3baeae0384a 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -2627,17 +2627,29 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
" Returns a new enumerator property definition.\n"
"\n"
" :arg items: sequence of enum items formatted:\n"
-" [(identifier, name, description, icon, number), ...] where the identifier is used\n"
-" for python access and other values are used for the interface.\n"
-" The three first elements of the tuples are mandatory.\n"
-" The fourth one is either the (unique!) number id of the item or, if followed by a fith element\n"
-" (which must be the numid), an icon string identifier or integer icon value (e.g. returned by icon()...).\n"
-" Note the item is optional.\n"
+" ``[(identifier, name, description, icon, number), ...]``.\n"
+"\n"
+" The first three elements of the tuples are mandatory.\n"
+"\n"
+" :identifier: The identifier is used for Python access.\n"
+" :name: Name for the interace.\n"
+" :description: Used for documentation and tooltips.\n"
+" :icon: An icon string identifier or integer icon value\n"
+" (e.g. returned by :class:`bpy.types.UILayout.icon`)\n"
+" :number: Unique value used as the identifier for this item (stored in file data).\n"
+" Use when the identifier may need to change.\n"
+"\n"
+" When an item only contains 4 items they define ``(identifier, name, description, number)``.\n"
+"\n"
" For dynamic values a callback can be passed which returns a list in\n"
" the same format as the static list.\n"
-" This function must take 2 arguments (self, context), **context may be None**.\n"
-" WARNING: There is a known bug with using a callback,\n"
-" Python must keep a reference to the strings returned or Blender will crash.\n"
+" This function must take 2 arguments ``(self, context)``, **context may be None**.\n"
+"\n"
+" .. warning::\n"
+"\n"
+" There is a known bug with using a callback,\n"
+" Python must keep a reference to the strings returned or Blender will crash.\n"
+"\n"
" :type items: sequence of string tuples or a function\n"
BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
@@ -2986,7 +2998,7 @@ static struct PyModuleDef props_module = {
"This module defines properties to extend Blender's internal data. The result of these functions"
" is used to assign properties to classes registered with Blender and can't be used directly.\n"
"\n"
- ".. warning:: All parameters to these functions must be passed as keywords.\n",
+ ".. note:: All parameters to these functions must be passed as keywords.\n",
-1, /* multiple "initialization" just copies the module dict. */
props_methods,
NULL, NULL, NULL, NULL
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 4bd30ba4dff..05bd55d3781 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -136,7 +136,9 @@ static void id_release_gc(struct ID *id)
PyGC_Head *g = gen->gc.gc_next;
while ((g = g->gc.gc_next) != gen) {
PyObject *ob = FROM_GC(g);
- if (PyType_IsSubtype(Py_TYPE(ob), &pyrna_struct_Type) || PyType_IsSubtype(Py_TYPE(ob), &pyrna_prop_Type)) {
+ if (PyType_IsSubtype(Py_TYPE(ob), &pyrna_struct_Type) ||
+ PyType_IsSubtype(Py_TYPE(ob), &pyrna_prop_Type))
+ {
BPy_DummyPointerRNA *ob_ptr = (BPy_DummyPointerRNA *)ob;
if (ob_ptr->ptr.id.data == id) {
pyrna_invalidate(ob_ptr);
@@ -358,9 +360,12 @@ static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item
#ifdef USE_MATHUTILS
#include "../mathutils/mathutils.h" /* so we can have mathutils callbacks */
-static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop,
- Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length);
-static short pyrna_rotation_euler_order_get(PointerRNA *ptr, PropertyRNA **prop_eul_order, const short order_fallback);
+static PyObject *pyrna_prop_array_subscript_slice(
+ BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop,
+ Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length);
+static short pyrna_rotation_euler_order_get(
+ PointerRNA *ptr, const short order_fallback,
+ PropertyRNA **r_prop_eul_order);
/* bpyrna vector/euler/quat callbacks */
static unsigned char mathutils_rna_array_cb_index = -1; /* index for our callbacks */
@@ -395,7 +400,7 @@ static int mathutils_rna_vector_get(BaseMathObject *bmo, int subtype)
if (subtype == MATHUTILS_CB_SUBTYPE_EUL) {
EulerObject *eul = (EulerObject *)bmo;
PropertyRNA *prop_eul_order = NULL;
- eul->order = pyrna_rotation_euler_order_get(&self->ptr, &prop_eul_order, eul->order);
+ eul->order = pyrna_rotation_euler_order_get(&self->ptr, eul->order, &prop_eul_order);
}
return 0;
@@ -442,7 +447,7 @@ static int mathutils_rna_vector_set(BaseMathObject *bmo, int subtype)
if (subtype == MATHUTILS_CB_SUBTYPE_EUL) {
EulerObject *eul = (EulerObject *)bmo;
PropertyRNA *prop_eul_order = NULL;
- short order = pyrna_rotation_euler_order_get(&self->ptr, &prop_eul_order, eul->order);
+ short order = pyrna_rotation_euler_order_get(&self->ptr, eul->order, &prop_eul_order);
if (order != eul->order) {
RNA_property_enum_set(&self->ptr, prop_eul_order, eul->order);
if (RNA_property_update_check(prop_eul_order)) {
@@ -562,16 +567,21 @@ static Mathutils_Callback mathutils_rna_matrix_cb = {
NULL
};
-static short pyrna_rotation_euler_order_get(PointerRNA *ptr, PropertyRNA **prop_eul_order, const short order_fallback)
+static short pyrna_rotation_euler_order_get(
+ PointerRNA *ptr, const short order_fallback,
+ PropertyRNA **r_prop_eul_order)
{
/* attempt to get order */
- if (*prop_eul_order == NULL)
- *prop_eul_order = RNA_struct_find_property(ptr, "rotation_mode");
+ if (*r_prop_eul_order == NULL) {
+ *r_prop_eul_order = RNA_struct_find_property(ptr, "rotation_mode");
+ }
- if (*prop_eul_order) {
- short order = RNA_property_enum_get(ptr, *prop_eul_order);
- if (order >= EULER_ORDER_XYZ && order <= EULER_ORDER_ZYX) /* could be quat or axisangle */
+ if (*r_prop_eul_order) {
+ short order = RNA_property_enum_get(ptr, *r_prop_eul_order);
+ /* could be quat or axisangle */
+ if (order >= EULER_ORDER_XYZ && order <= EULER_ORDER_ZYX) {
return order;
+ }
}
return order_fallback;
@@ -639,7 +649,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((VectorObject *)ret)->vec);
}
else {
- PyObject *vec_cb = Vector_CreatePyObject_cb(ret, len, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_VEC);
+ PyObject *vec_cb = Vector_CreatePyObject_cb(
+ ret, len, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_VEC);
Py_DECREF(ret); /* the vector owns now */
ret = vec_cb; /* return the vector instead */
}
@@ -652,7 +663,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((MatrixObject *)ret)->matrix);
}
else {
- PyObject *mat_cb = Matrix_CreatePyObject_cb(ret, 4, 4, mathutils_rna_matrix_cb_index, 0);
+ PyObject *mat_cb = Matrix_CreatePyObject_cb(
+ ret, 4, 4, mathutils_rna_matrix_cb_index, 0);
Py_DECREF(ret); /* the matrix owns now */
ret = mat_cb; /* return the matrix instead */
}
@@ -663,7 +675,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((MatrixObject *)ret)->matrix);
}
else {
- PyObject *mat_cb = Matrix_CreatePyObject_cb(ret, 3, 3, mathutils_rna_matrix_cb_index, 0);
+ PyObject *mat_cb = Matrix_CreatePyObject_cb(
+ ret, 3, 3, mathutils_rna_matrix_cb_index, 0);
Py_DECREF(ret); /* the matrix owns now */
ret = mat_cb; /* return the matrix instead */
}
@@ -675,14 +688,16 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
if (is_thick) {
/* attempt to get order, only needed for thick types since wrapped with update via callbacks */
PropertyRNA *prop_eul_order = NULL;
- short order = pyrna_rotation_euler_order_get(ptr, &prop_eul_order, EULER_ORDER_XYZ);
+ short order = pyrna_rotation_euler_order_get(ptr, EULER_ORDER_XYZ, &prop_eul_order);
ret = Euler_CreatePyObject(NULL, order, NULL); /* TODO, get order from RNA */
RNA_property_float_get_array(ptr, prop, ((EulerObject *)ret)->eul);
}
else {
/* order will be updated from callback on use */
- PyObject *eul_cb = Euler_CreatePyObject_cb(ret, EULER_ORDER_XYZ, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_EUL); // TODO, get order from RNA
+ // TODO, get order from RNA
+ PyObject *eul_cb = Euler_CreatePyObject_cb(
+ ret, EULER_ORDER_XYZ, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_EUL);
Py_DECREF(ret); /* the euler owns now */
ret = eul_cb; /* return the euler instead */
}
@@ -693,7 +708,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((QuaternionObject *)ret)->quat);
}
else {
- PyObject *quat_cb = Quaternion_CreatePyObject_cb(ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_QUAT);
+ PyObject *quat_cb = Quaternion_CreatePyObject_cb(
+ ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_QUAT);
Py_DECREF(ret); /* the quat owns now */
ret = quat_cb; /* return the quat instead */
}
@@ -707,7 +723,8 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
RNA_property_float_get_array(ptr, prop, ((ColorObject *)ret)->col);
}
else {
- PyObject *col_cb = Color_CreatePyObject_cb(ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_COLOR);
+ PyObject *col_cb = Color_CreatePyObject_cb(
+ ret, mathutils_rna_array_cb_index, MATHUTILS_CB_SUBTYPE_COLOR);
Py_DECREF(ret); /* the color owns now */
ret = col_cb; /* return the color instead */
}
@@ -738,9 +755,11 @@ thick_wrap_slice:
}
/* same as RNA_enum_value_from_id but raises an exception */
-int pyrna_enum_value_from_id(EnumPropertyItem *item, const char *identifier, int *value, const char *error_prefix)
+int pyrna_enum_value_from_id(
+ EnumPropertyItem *item, const char *identifier, int *r_value,
+ const char *error_prefix)
{
- if (RNA_enum_value_from_id(item, identifier, value) == 0) {
+ if (RNA_enum_value_from_id(item, identifier, r_value) == 0) {
const char *enum_str = BPy_enum_as_string(item);
PyErr_Format(PyExc_ValueError,
"%s: '%.200s' not found in (%s)",
@@ -1165,7 +1184,9 @@ static const char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop)
}
-static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *val, const char *error_prefix)
+static int pyrna_string_to_enum(
+ PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *r_value,
+ const char *error_prefix)
{
const char *param = _PyUnicode_AsString(item);
@@ -1176,7 +1197,7 @@ static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *pr
return -1;
}
else {
- if (!RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, val)) {
+ if (!RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, r_value)) {
const char *enum_str = pyrna_enum_as_string(ptr, prop);
PyErr_Format(PyExc_TypeError,
"%.200s enum \"%.200s\" not found in (%.200s)",
@@ -1253,7 +1274,9 @@ error:
}
/* 'value' _must_ be a set type, error check before calling */
-int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_value, const char *error_prefix)
+int pyrna_set_to_enum_bitfield(
+ EnumPropertyItem *items, PyObject *value, int *r_value,
+ const char *error_prefix)
{
/* set of enum items, concatenate all values with OR */
int ret, flag = 0;
@@ -1286,7 +1309,9 @@ int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_
return 0;
}
-static int pyrna_prop_to_enum_bitfield(PointerRNA *ptr, PropertyRNA *prop, PyObject *value, int *r_value, const char *error_prefix)
+static int pyrna_prop_to_enum_bitfield(
+ PointerRNA *ptr, PropertyRNA *prop, PyObject *value, int *r_value,
+ const char *error_prefix)
{
EnumPropertyItem *item;
int ret;
@@ -1505,9 +1530,13 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
return ret;
}
-/* This function is used by operators and converting dicts into collections.
- * Its takes keyword args and fills them with property values */
-int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const char *error_prefix)
+/**
+ * This function is used by operators and converting dicts into collections.
+ * Its takes keyword args and fills them with property values
+ */
+int pyrna_pydict_to_props(
+ PointerRNA *ptr, PyObject *kw, const bool all_args,
+ const char *error_prefix)
{
int error_val = 0;
int totkw;
@@ -1582,7 +1611,9 @@ static PyObject *pyrna_func_to_py(const PointerRNA *ptr, FunctionRNA *func)
}
-static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value, const char *error_prefix)
+static int pyrna_py_to_prop(
+ PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *value,
+ const char *error_prefix)
{
/* XXX hard limits should be checked here */
const int type = RNA_property_type(prop);
@@ -1713,7 +1744,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
}
else {
/* same as unicode */
- if (data) *((char **)data) = (char *)param; /*XXX, this is suspect but needed for function calls, need to see if theres a better way */
+ /* XXX, this is suspect but needed for function calls, need to see if theres a better way */
+ if (data) *((char **)data) = (char *)param;
else RNA_property_string_set(ptr, prop, param);
}
}
@@ -1753,7 +1785,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
}
else {
/* same as bytes */
- if (data) *((char **)data) = (char *)param; /*XXX, this is suspect but needed for function calls, need to see if theres a better way */
+ /* XXX, this is suspect but needed for function calls, need to see if theres a better way */
+ if (data) *((char **)data) = (char *)param;
else RNA_property_string_set(ptr, prop, param);
}
#ifdef USE_STRING_COERCE
@@ -1801,8 +1834,8 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
* if the prop is not an operator type and the pyobject is an operator,
* use its properties in place of its self.
*
- * this is so bad that its almost a good reason to do away with fake 'self.properties -> self' class mixing
- * if this causes problems in the future it should be removed.
+ * this is so bad that its almost a good reason to do away with fake 'self.properties -> self'
+ * class mixing if this causes problems in the future it should be removed.
*/
if ((ptr_type == &RNA_AnyType) &&
(BPy_StructRNA_Check(value)) &&
@@ -1817,7 +1850,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
* forward back to pyrna_pydict_to_props */
if (RNA_struct_is_a(ptr_type, &RNA_OperatorProperties) && PyDict_Check(value)) {
PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
- return pyrna_pydict_to_props(&opptr, value, 0, error_prefix);
+ return pyrna_pydict_to_props(&opptr, value, false, error_prefix);
}
/* another exception, allow to pass a collection as an RNA property */
@@ -1983,7 +2016,10 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
else
RNA_property_collection_add(ptr, prop, &itemptr);
- if (pyrna_pydict_to_props(&itemptr, item, 1, "Converting a python list to an RNA collection") == -1) {
+ if (pyrna_pydict_to_props(
+ &itemptr, item, true,
+ "Converting a python list to an RNA collection") == -1)
+ {
PyObject *msg = PyC_ExceptionBuffer();
const char *msg_char = _PyUnicode_AsString(msg);
@@ -2245,19 +2281,21 @@ static PyObject *pyrna_prop_collection_subscript_str(BPy_PropertyRNA *self, cons
}
/* static PyObject *pyrna_prop_array_subscript_str(BPy_PropertyRNA *self, char *keyname) */
-/* special case: bpy.data.objects["some_id_name", "//some_lib_name.blend"]
- * also for: bpy.data.objects.get(("some_id_name", "//some_lib_name.blend"), fallback)
+/**
+ * Special case: `bpy.data.objects["some_id_name", "//some_lib_name.blend"]`
+ * also for: `bpy.data.objects.get(("some_id_name", "//some_lib_name.blend"), fallback)`
*
- * note:
+ * \note
* error codes since this is not to be called directly from python,
- * this matches pythons __contains__ values capi.
- * -1: exception set
- * 0: not found
- * 1: found */
-static int pyrna_prop_collection_subscript_str_lib_pair_ptr(BPy_PropertyRNA *self, PyObject *key,
- const char *err_prefix, const short err_not_found,
- PointerRNA *r_ptr
- )
+ * this matches pythons `__contains__` values capi.
+ * - -1: exception set
+ * - 0: not found
+ * - 1: found
+ */
+static int pyrna_prop_collection_subscript_str_lib_pair_ptr(
+ BPy_PropertyRNA *self, PyObject *key,
+ const char *err_prefix, const short err_not_found,
+ PointerRNA *r_ptr)
{
const char *keyname;
@@ -2342,8 +2380,9 @@ static int pyrna_prop_collection_subscript_str_lib_pair_ptr(BPy_PropertyRNA *sel
}
}
-static PyObject *pyrna_prop_collection_subscript_str_lib_pair(BPy_PropertyRNA *self, PyObject *key,
- const char *err_prefix, const bool err_not_found)
+static PyObject *pyrna_prop_collection_subscript_str_lib_pair(
+ BPy_PropertyRNA *self, PyObject *key,
+ const char *err_prefix, const bool err_not_found)
{
PointerRNA ptr;
const int contains = pyrna_prop_collection_subscript_str_lib_pair_ptr(self, key, err_prefix, err_not_found, &ptr);
@@ -2395,8 +2434,9 @@ static PyObject *pyrna_prop_collection_subscript_slice(BPy_PropertyRNA *self, Py
* note: could also use pyrna_prop_array_to_py_index(self, count) in a loop but its a lot slower
* since at the moment it reads (and even allocates) the entire array for each index.
*/
-static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop,
- Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length)
+static PyObject *pyrna_prop_array_subscript_slice(
+ BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop,
+ Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length)
{
int count, totdim;
PyObject *tuple;
@@ -4588,9 +4628,10 @@ static PyObject *pyrna_prop_collection_find(BPy_PropertyRNA *self, PyObject *key
return PyLong_FromLong(index);
}
-static bool foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
- /* values to assign */
- RawPropertyType *raw_type, int *attr_tot, bool *attr_signed)
+static bool foreach_attr_type(
+ BPy_PropertyRNA *self, const char *attr,
+ /* values to assign */
+ RawPropertyType *raw_type, int *attr_tot, bool *attr_signed)
{
PropertyRNA *prop;
bool attr_ok = true;
@@ -4618,12 +4659,12 @@ static bool foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
}
/* pyrna_prop_collection_foreach_get/set both use this */
-static int foreach_parse_args(BPy_PropertyRNA *self, PyObject *args,
+static int foreach_parse_args(
+ BPy_PropertyRNA *self, PyObject *args,
- /* values to assign */
- const char **attr, PyObject **seq, int *tot, int *size,
- RawPropertyType *raw_type, int *attr_tot, bool *attr_signed
- )
+ /* values to assign */
+ const char **attr, PyObject **seq, int *tot, int *size,
+ RawPropertyType *raw_type, int *attr_tot, bool *attr_signed)
{
#if 0
int array_tot;
@@ -7500,7 +7541,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
}
}
- if (err != -1 && (is_staticmethod || is_classmethod || py_class_instance)) { /* Initializing the class worked, now run its invoke function */
+ /* Initializing the class worked, now run its invoke function */
+ if (err != -1 && (is_staticmethod || is_classmethod || py_class_instance)) {
PyObject *item = PyObject_GetAttrString((PyObject *)py_class, RNA_function_identifier(func));
if (item) {
@@ -7913,7 +7955,9 @@ static PyObject *pyrna_register_class(PyObject *UNUSED(self), PyObject *py_class
}
-static int pyrna_srna_contains_pointer_prop_srna(StructRNA *srna_props, StructRNA *srna, const char **prop_identifier)
+static int pyrna_srna_contains_pointer_prop_srna(
+ StructRNA *srna_props, StructRNA *srna,
+ const char **r_prop_identifier)
{
PropertyRNA *prop;
LinkData *link;
@@ -7928,7 +7972,7 @@ static int pyrna_srna_contains_pointer_prop_srna(StructRNA *srna_props, StructRN
RNA_pointer_create(NULL, &RNA_Struct, srna_props, &tptr);
if (RNA_property_pointer_type(&tptr, prop) == srna) {
- *prop_identifier = RNA_property_identifier(prop);
+ *r_prop_identifier = RNA_property_identifier(prop);
return 1;
}
}
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index c5d4a346f56..e38d4f095d6 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -181,7 +181,7 @@ PyObject *pyrna_id_CreatePyObject(struct ID *id);
bool pyrna_id_FromPyObject(PyObject *obj, struct ID **id);
/* operators also need this to set args */
-int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, int all_args, const char *error_prefix);
+int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const bool all_args, const char *error_prefix);
PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
unsigned int *pyrna_set_to_enum_bitmap(
diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c
index c3bb588f7eb..50dd4618166 100644
--- a/source/blender/python/intern/gpu.c
+++ b/source/blender/python/intern/gpu.c
@@ -330,10 +330,10 @@ PyObject *GPU_initPython(void)
/* gpu.offscreen */
PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
- PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module);
+ PyDict_SetItem(PyImport_GetModuleDict(), PyModule_GetNameObject(module), module);
return module;
}
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 635090869ea..5c505247a97 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -638,30 +638,30 @@ PyMODINIT_FUNC PyInit_mathutils(void)
/* XXX, python doesnt do imports with this usefully yet
* 'from mathutils.geometry import PolyFill'
* ...fails without this. */
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
PyModule_AddObject(mod, "interpolate", (submodule = PyInit_mathutils_interpolate()));
/* XXX, python doesnt do imports with this usefully yet
* 'from mathutils.geometry import PolyFill'
* ...fails without this. */
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
#ifndef MATH_STANDALONE
/* Noise submodule */
PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
/* BVHTree submodule */
PyModule_AddObject(mod, "bvhtree", (submodule = PyInit_mathutils_bvhtree()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
/* KDTree submodule */
PyModule_AddObject(mod, "kdtree", (submodule = PyInit_mathutils_kdtree()));
- PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
Py_INCREF(submodule);
#endif
diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m
index d42d0ee8ebb..ba7ee0a8936 100644
--- a/source/blender/quicktime/apple/qtkit_import.m
+++ b/source/blender/quicktime/apple/qtkit_import.m
@@ -200,7 +200,7 @@ static ImBuf *nsImageToiBuf(NSImage *sourceImage, int width, int height)
/* Convert the image in a RGBA 32bit format */
/* As Core Graphics does not support contextes with non premutliplied alpha,
- we need to get alpha key values in a separate batch */
+ * we need to get alpha key values in a separate batch */
/* First get RGB values w/o Alpha to avoid pre-multiplication, 32bit but last byte is unused */
blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index ce0691b7632..39f62f9fc33 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -231,8 +231,9 @@ struct RenderStats *RE_GetStats(struct Render *re);
void RE_ResultGet32(struct Render *re, unsigned int *rect);
void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect, const int view_id);
-void RE_render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd,
- struct ImBuf *ibuf, const int view_id);
+void RE_render_result_rect_from_ibuf(
+ struct RenderResult *rr, struct RenderData *rd,
+ struct ImBuf *ibuf, const int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname);
@@ -249,8 +250,8 @@ struct Object *RE_GetCamera(struct Render *re); /* return camera override if set
void RE_SetOverrideCamera(struct Render *re, struct Object *camera);
void RE_SetCamera(struct Render *re, struct Object *camera);
void RE_SetEnvmapCamera(struct Render *re, struct Object *cam_ob, float viewscale, float clipsta, float clipend);
-void RE_SetWindow(struct Render *re, rctf *viewplane, float clipsta, float clipend);
-void RE_SetOrtho(struct Render *re, rctf *viewplane, float clipsta, float clipend);
+void RE_SetWindow(struct Render *re, const rctf *viewplane, float clipsta, float clipend);
+void RE_SetOrtho(struct Render *re, const rctf *viewplane, float clipsta, float clipend);
void RE_SetPixelSize(struct Render *re, float pixsize);
/* option to set viewmatrix before making dbase */
@@ -258,10 +259,12 @@ void RE_SetView(struct Render *re, float mat[4][4]);
/* get current view and window transform */
void RE_GetView(struct Render *re, float mat[4][4]);
-void RE_GetViewPlane(struct Render *re, rctf *viewplane, rcti *disprect);
+void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
/* make or free the dbase */
-void RE_Database_FromScene(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, int use_camera_view);
+void RE_Database_FromScene(
+ struct Render *re, struct Main *bmain, struct Scene *scene,
+ unsigned int lay, int use_camera_view);
void RE_Database_Preprocess(struct Render *re);
void RE_Database_Free(struct Render *re);
@@ -304,11 +307,16 @@ void RE_SetReports(struct Render *re, struct ReportList *reports);
void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene);
bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode);
-bool RE_WriteRenderResult(struct ReportList *reports, RenderResult *rr, const char *filename, struct ImageFormatData *imf, const bool multiview, const char *view);
-struct RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
+bool RE_WriteRenderResult(
+ struct ReportList *reports, RenderResult *rr, const char *filename,
+ struct ImageFormatData *imf, const bool multiview, const char *view);
+struct RenderResult *RE_MultilayerConvert(
+ void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
extern const float default_envmap_layout[];
-bool RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]);
+bool RE_WriteEnvmapResult(
+ struct ReportList *reports, struct Scene *scene, struct EnvMap *env,
+ const char *relpath, const char imtype, float layout[12]);
/* do a full sample buffer compo */
void RE_MergeFullSample(struct Render *re, struct Main *bmain, struct Scene *sce, struct bNodeTree *ntree);
@@ -326,7 +334,9 @@ void RE_current_scene_update_cb(struct Render *re, void *handle, void (*f)(void
/* should move to kernel once... still unsure on how/where */
float RE_filter_value(int type, float x);
/* vector blur zbuffer method */
-void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect);
+void RE_zbuf_accumulate_vecblur(
+ struct NodeBlurData *nbd, int xsize, int ysize, float *newrect,
+ const float *imgrect, float *vecbufrect, const float *zbufrect);
int RE_seq_render_active(struct Scene *scene, struct RenderData *rd);
@@ -351,7 +361,9 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int pas
#define RE_BAKE_DERIVATIVE 13
#define RE_BAKE_VERTEX_COLORS 14
-void RE_Database_Baking(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, const int type, struct Object *actob);
+void RE_Database_Baking(
+ struct Render *re, struct Main *bmain, struct Scene *scene,
+ unsigned int lay, const int type, struct Object *actob);
void RE_DataBase_GetView(struct Render *re, float mat[4][4]);
void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]);
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 6de5da3795a..b3a5ccdae17 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -180,6 +180,7 @@ struct Render {
float jit[32][2];
float mblur_jit[32][2];
ListBase *qmcsamplers;
+ int num_qmc_samplers;
/* shadow counter, detect shadow-reuse for shaders */
int shadowsamplenr[BLENDER_MAX_THREADS];
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index 308903c6c6d..7254fd25ee6 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -90,7 +90,7 @@ extern void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]);
extern void ray_trace(ShadeInput *shi, ShadeResult *);
extern void ray_ao(ShadeInput *shi, float ao[3], float env[3]);
extern void init_jitter_plane(LampRen *lar);
-extern void init_ao_sphere(struct World *wrld);
+extern void init_ao_sphere(Render *re, struct World *wrld);
extern void init_render_qmcsampler(Render *re);
extern void free_render_qmcsampler(Render *re);
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
index f511042749e..2104315dc00 100644
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -145,8 +145,8 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i
if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
/* check if intersection is within ray length */
if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- r_uv[0] = uv[0];
- r_uv[1] = uv[1];
+ r_uv[0] = -uv[0];
+ r_uv[1] = -uv[1];
*lambda = l;
return 1;
}
@@ -157,8 +157,8 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i
if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
/* check if intersection is within ray length */
if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
- r_uv[0] = uv[0];
- r_uv[1] = uv[1];
+ r_uv[0] = -uv[0];
+ r_uv[1] = -uv[1];
*lambda = l;
return 2;
}
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 907974e20dc..86961cdd169 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -4192,7 +4192,7 @@ static void split_quads(ObjectRen *obr, int dir)
vlr= RE_findOrAddVlak(obr, a);
/* test if rendering as a quad or triangle, skip wire */
- if (vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
+ if ((vlr->flag & R_STRAND)==0 && (vlr->mat->material_type != MA_TYPE_WIRE)) {
if (vlr->v4) {
@@ -5230,7 +5230,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(&re->wrld);
+ init_ao_sphere(re, &re->wrld);
}
/* still bad... doing all */
@@ -5956,7 +5956,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT))
if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
- init_ao_sphere(&re->wrld);
+ init_ao_sphere(re, &re->wrld);
}
/* still bad... doing all */
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
index c5c3b6bbf94..b3d31e3b93a 100644
--- a/source/blender/render/intern/source/occlusion.c
+++ b/source/blender/render/intern/source/occlusion.c
@@ -115,6 +115,8 @@ typedef struct OcclusionTree {
int doindirect;
OcclusionCache *cache;
+
+ int num_threads;
} OcclusionTree;
typedef struct OcclusionThread {
@@ -641,6 +643,7 @@ static void occ_build_sh_normalize(OccNode *node)
static OcclusionTree *occ_tree_build(Render *re)
{
+ const int num_threads = re->r.threads;
OcclusionTree *tree;
ObjectInstanceRen *obi;
ObjectRen *obr;
@@ -679,7 +682,7 @@ static OcclusionTree *occ_tree_build(Render *re)
BLI_memarena_use_calloc(tree->arena);
if (re->wrld.aomode & WO_AOCACHE)
- tree->cache = MEM_callocN(sizeof(OcclusionCache) * BLENDER_MAX_THREADS, "OcclusionCache");
+ tree->cache = MEM_callocN(sizeof(OcclusionCache) * num_threads, "OcclusionCache");
tree->face = MEM_callocN(sizeof(OccFace) * totface, "OcclusionFace");
tree->co = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionCo");
@@ -730,9 +733,11 @@ static OcclusionTree *occ_tree_build(Render *re)
if (!(re->test_break(re->tbh)))
occ_build_sh_normalize(tree->root);
- for (a = 0; a < BLENDER_MAX_THREADS; a++)
+ for (a = 0; a < num_threads; a++)
tree->stack[a] = MEM_callocN(sizeof(OccNode) * TOTCHILD * (tree->maxdepth + 1), "OccStack");
+ tree->num_threads = num_threads;
+
return tree;
}
@@ -742,7 +747,7 @@ static void occ_free_tree(OcclusionTree *tree)
if (tree) {
if (tree->arena) BLI_memarena_free(tree->arena);
- for (a = 0; a < BLENDER_MAX_THREADS; a++)
+ for (a = 0; a < tree->num_threads; a++)
if (tree->stack[a])
MEM_freeN(tree->stack[a]);
if (tree->occlusion) MEM_freeN(tree->occlusion);
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 6b910dc9fc4..1ee905c596c 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -355,7 +355,7 @@ Scene *RE_GetScene(Render *re)
* Same as #RE_AcquireResultImage but creating the necessary views to store the result
* fill provided result struct with a copy of thew views of what is done so far the
* #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews
-*/
+ */
void RE_AcquireResultImageViews(Render *re, RenderResult *rr)
{
memset(rr, 0, sizeof(RenderResult));
@@ -931,7 +931,7 @@ void render_update_anim_renderdata(Render *re, RenderData *rd)
BLI_duplicatelist(&re->r.views, &rd->views);
}
-void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
+void RE_SetWindow(Render *re, const rctf *viewplane, float clipsta, float clipend)
{
/* re->ok flag? */
@@ -946,7 +946,7 @@ void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
}
-void RE_SetOrtho(Render *re, rctf *viewplane, float clipsta, float clipend)
+void RE_SetOrtho(Render *re, const rctf *viewplane, float clipsta, float clipend)
{
/* re->ok flag? */
@@ -967,15 +967,17 @@ void RE_SetView(Render *re, float mat[4][4])
invert_m4_m4(re->viewinv, re->viewmat);
}
-void RE_GetViewPlane(Render *re, rctf *viewplane, rcti *disprect)
+void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect)
{
- *viewplane = re->viewplane;
+ *r_viewplane = re->viewplane;
/* make disprect zero when no border render, is needed to detect changes in 3d view render */
- if (re->r.mode & R_BORDER)
- *disprect = re->disprect;
- else
- BLI_rcti_init(disprect, 0, 0, 0, 0);
+ if (re->r.mode & R_BORDER) {
+ *r_disprect = re->disprect;
+ }
+ else {
+ BLI_rcti_init(r_disprect, 0, 0, 0, 0);
+ }
}
void RE_GetView(Render *re, float mat[4][4])
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 9aac5ed1f1d..26a0b0c71b4 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -174,10 +174,11 @@ void freeraytree(Render *re)
#ifdef RE_RAYCOUNTER
{
+ const int num_threads = re->r.threads;
RayCounter sum;
memset(&sum, 0, sizeof(sum));
int i;
- for (i=0; i<BLENDER_MAX_THREADS; i++)
+ for (i=0; i<num_threads; i++)
RE_RC_MERGE(&sum, re_rc_counter+i);
RE_RC_INFO(&sum);
}
@@ -1186,7 +1187,9 @@ static void QMC_sampleHemiCosine(float vec[3], QMCSampler *qsa, int thread, int
/* called from convertBlenderScene.c */
void init_render_qmcsampler(Render *re)
{
- re->qmcsamplers= MEM_callocN(sizeof(ListBase)*BLENDER_MAX_THREADS, "QMCListBase");
+ const int num_threads = re->r.threads;
+ re->qmcsamplers= MEM_callocN(sizeof(ListBase)*num_threads, "QMCListBase");
+ re->num_qmc_samplers = num_threads;
}
static QMCSampler *get_thread_qmcsampler(Render *re, int thread, int type, int tot)
@@ -1220,7 +1223,7 @@ void free_render_qmcsampler(Render *re)
if (re->qmcsamplers) {
QMCSampler *qsa, *next;
int a;
- for (a=0; a<BLENDER_MAX_THREADS; a++) {
+ for (a = 0; a < re->num_qmc_samplers; a++) {
for (qsa=re->qmcsamplers[a].first; qsa; qsa=next) {
next= qsa->next;
QMC_freeSampler(qsa);
@@ -1695,9 +1698,10 @@ static void DS_energy(float *sphere, int tot, float vec[3])
/* called from convertBlenderScene.c */
/* creates an equally distributed spherical sample pattern */
/* and allocates threadsafe memory */
-void init_ao_sphere(World *wrld)
+void init_ao_sphere(Render *re, World *wrld)
{
/* fixed random */
+ const int num_threads = re->r.threads;
RNG *rng;
float *fp;
int a, tot, iter= 16;
@@ -1721,7 +1725,7 @@ void init_ao_sphere(World *wrld)
}
/* tables */
- wrld->aotables= MEM_mallocN(BLENDER_MAX_THREADS*3*tot*sizeof(float), "AO tables");
+ wrld->aotables= MEM_mallocN(num_threads*3*tot*sizeof(float), "AO tables");
BLI_rng_free(rng);
}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 513cfa6df7d..b4a14f5337d 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -3653,7 +3653,8 @@ void render_realtime_texture(ShadeInput *shi, Image *ima)
if (firsttime) {
BLI_lock_thread(LOCK_IMAGE);
if (firsttime) {
- for (a=0; a<BLENDER_MAX_THREADS; a++) {
+ const int num_threads = BLI_system_thread_count();
+ for (a = 0; a < num_threads; a++) {
memset(&imatex[a], 0, sizeof(Tex));
BKE_texture_default(&imatex[a]);
imatex[a].type= TEX_IMAGE;
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index d3d26011a57..76e6ca8d467 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -1006,7 +1006,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0f;
+ if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
else zn = atan2f(yn, xn);
har->sin = sinf(zn);
@@ -1136,7 +1136,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
- if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0;
+ if (yn == 0.0f && xn >= 0.0f) zn = 0.0f;
else zn = atan2f(yn, xn);
har->sin = sinf(zn);
diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c
index 553710b4367..26ca3ad50e0 100644
--- a/source/blender/render/intern/source/sss.c
+++ b/source/blender/render/intern/source/sss.c
@@ -279,13 +279,19 @@ static void build_Rd_table(ScatterSettings *ss)
for (i= 0; i < size; i++) {
r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE);
- /*if (r < ss->invsigma_t_*ss->invsigma_t_)
- r= ss->invsigma_t_*ss->invsigma_t_;*/
+#if 0
+ if (r < ss->invsigma_t_*ss->invsigma_t_) {
+ r= ss->invsigma_t_*ss->invsigma_t_;
+ }
+#endif
ss->tableRd[i]= Rd(ss, sqrtf(r));
r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE);
- /*if (r < ss->invsigma_t_)
- r= ss->invsigma_t_;*/
+#if 0
+ if (r < ss->invsigma_t_) {
+ r= ss->invsigma_t_;
+ }
+#endif
ss->tableRd2[i]= Rd(ss, r);
}
}
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index d3a1dcfd8ce..9f777631e52 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -2883,14 +2883,17 @@ static void set_quad_bezier_ipo(float fac, float *data)
data[2]= fac*fac;
}
-void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect)
+void RE_zbuf_accumulate_vecblur(
+ NodeBlurData *nbd, int xsize, int ysize, float *newrect,
+ const float *imgrect, float *vecbufrect, const float *zbufrect)
{
ZSpan zspan;
DrawBufPixel *rectdraw, *dr;
static float jit[256][2];
float v1[3], v2[3], v3[3], v4[3], fx, fy;
- float *rectvz, *dvz, *dimg, *dvec1, *dvec2, *dz, *dz1, *dz2, *rectz;
- float *minvecbufrect= NULL, *rectweight, *rw, *rectmax, *rm, *ro;
+ const float *dimg, *dz, *ro;
+ float *rectvz, *dvz, *dvec1, *dvec2, *dz1, *dz2, *rectz;
+ float *minvecbufrect= NULL, *rectweight, *rw, *rectmax, *rm;
float maxspeedsq= (float)nbd->maxspeed*nbd->maxspeed;
int y, x, step, maxspeed=nbd->maxspeed, samples= nbd->samples;
int tsktsk= 0;
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 3fbbea72046..127525bb857 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -114,6 +114,8 @@ void WM_autosave_init(struct wmWindowManager *wm);
void WM_recover_last_session(struct bContext *C, struct ReportList *reports);
void WM_file_tag_modified(const struct bContext *C);
+void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports);
+
/* mouse cursors */
void WM_cursor_set(struct wmWindow *win, int curs);
void WM_cursor_modal_set(struct wmWindow *win, int curs);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 4a48143b87b..51fbabac638 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -52,7 +52,7 @@
#include "RNA_access.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_global.h"
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 638d6fe96d2..a85e39ac65e 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -482,8 +482,6 @@ static void wm_file_read_post(bContext *C, bool is_startup_file)
BPY_python_reset(C);
addons_loaded = true;
}
-#else
- UNUSED_VARS(is_startup_file);
#endif /* WITH_PYTHON */
WM_operatortype_last_properties_clear_all();
@@ -492,8 +490,12 @@ static void wm_file_read_post(bContext *C, bool is_startup_file)
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
- /* would otherwise be handled by event loop */
- if (G.background) {
+ /* Would otherwise be handled by event loop.
+ *
+ * Disabled for startup file, since it causes problems when PyDrivers are used in the startup file.
+ * While its possible state of startup file may be wrong,
+ * in this case users nearly always load a file to replace the startup file. */
+ if (G.background && (is_startup_file == false)) {
Main *bmain = CTX_data_main(C);
BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C));
}
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index f3792e0bac6..8195212f3c3 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -62,7 +62,7 @@
#include "BLO_readfile.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_library.h"
@@ -691,9 +691,13 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN
return OPERATOR_CANCELLED;
}
-/* Note that IDs listed in lapp_data items *must* have been removed from bmain by caller. */
+/**
+ * \param library if given, all IDs from that library will be removed and reloaded. Otherwise, IDs must have already
+ * been removed from \a bmain, and added to \a lapp_data.
+ */
static void lib_relocate_do(
- Main *bmain, WMLinkAppendData *lapp_data, ReportList *reports, AssetEngineType *aet, const bool do_reload)
+ Main *bmain, Scene *scene,
+ Library *library, WMLinkAppendData *lapp_data, ReportList *reports, AssetEngineType *aet, const bool do_reload)
{
ListBase *lbarray[MAX_LIBARRAY];
int lba_idx;
@@ -701,6 +705,36 @@ static void lib_relocate_do(
LinkNode *itemlink;
int item_idx;
+ /* Remove all IDs to be reloaded from Main. */
+ if (library) {
+ lba_idx = set_listbasepointers(bmain, lbarray);
+ while (lba_idx--) {
+ ID *id = lbarray[lba_idx]->first;
+ const short idcode = id ? GS(id->name) : 0;
+
+ if (!id || !BKE_idcode_is_linkable(idcode)) {
+ /* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */
+ continue;
+ }
+
+ for (; id; id = id->next) {
+ if (id->lib == library) {
+ WMLinkAppendDataItem *item;
+
+ /* We remove it from current Main, and add it to items to link... */
+ /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitely linked here... */
+ BLI_remlink(lbarray[lba_idx], id);
+ item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, NULL, id);
+ BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries);
+
+#ifdef PRINT_DEBUG
+ printf("\tdatablock to seek for: %s\n", id->name);
+#endif
+ }
+ }
+ }
+ }
+
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true);
/* We do not want any instanciation here! */
@@ -839,6 +873,43 @@ static void lib_relocate_do(
}
}
}
+
+ BKE_main_lib_objects_recalc_all(bmain);
+ IMB_colormanagement_check_file_config(bmain);
+
+ /* important we unset, otherwise these object wont
+ * link into other scenes from this blend file */
+ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
+
+ /* recreate dependency graph to include new objects */
+ DAG_scene_relations_rebuild(bmain, scene);
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
+}
+
+void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
+{
+ if (!BLO_has_bfile_extension(lib->filepath)) {
+ BKE_reportf(reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->filepath);
+ return;
+ }
+
+ if (!BLI_exists(lib->filepath)) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Trying to reload library '%s' from invalid path '%s'", lib->id.name, lib->filepath);
+ return;
+ }
+
+ WMLinkAppendData *lapp_data = wm_link_append_data_new(0);
+
+ wm_link_append_data_library_add(lapp_data, lib->filepath);
+
+ lib_relocate_do(CTX_data_main(C), CTX_data_scene(C), lib, lapp_data, reports, NULL, true);
+
+ wm_link_append_data_free(lapp_data);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
}
static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
@@ -855,9 +926,6 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
PropertyRNA *prop;
WMLinkAppendData *lapp_data;
- ListBase *lbarray[MAX_LIBARRAY];
- int lba_idx;
-
char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
short flag = 0;
@@ -949,50 +1017,10 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
}
}
- lba_idx = set_listbasepointers(bmain, lbarray);
- while (lba_idx--) {
- ID *id = lbarray[lba_idx]->first;
- const short idcode = id ? GS(id->name) : 0;
-
- if (!id || !BKE_idcode_is_linkable(idcode)) {
- /* No need to reload non-linkable datatypes, those will get relinked with their 'users ID'. */
- continue;
- }
-
- for (; id; id = id->next) {
- if (id->lib == lib) {
- WMLinkAppendDataItem *item;
-
- /* We remove it from current Main, and add it to items to link... */
- /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitely linked here... */
- BLI_remlink(lbarray[lba_idx], id);
- item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, NULL, id);
- BLI_BITMAP_SET_ALL(item->libraries, true, lapp_data->num_libraries);
-
-#ifdef PRINT_DEBUG
- printf("\tdatablock to seek for: %s\n", id->name);
-#endif
- }
- }
- }
-
- lib_relocate_do(bmain, lapp_data, op->reports, NULL, do_reload);
+ lib_relocate_do(bmain, scene, lib, lapp_data, op->reports, NULL, do_reload);
wm_link_append_data_free(lapp_data);
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
-
- /* important we unset, otherwise these object wont
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DAG_scene_relations_rebuild(bmain, scene);
-
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free();
-
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
BLI_strncpy(G.lib, root, FILE_MAX);
@@ -1066,9 +1094,10 @@ typedef struct AssetUpdateCheckEngine {
AssetEngine *ae;
/* Note: We cannot store IDs themselves in non-locking async task... so we'll have to check again for
- * UUID/IDs mapping on each update call... Not ideal, but don't think it will be that big of an override
+ * UUID/IDs mapping on each update call... Not ideal, but don't think it will be that big of a bottleneck
* in practice. */
AssetUUIDList uuids;
+ int allocated_uuids;
int ae_job_id;
short status;
} AssetUpdateCheckEngine;
@@ -1170,13 +1199,16 @@ static void asset_update_engines_uuids_fetch(
id->uuid->tag = (id->tag & LIB_TAG_MISSING) ? UUID_TAG_ASSET_MISSING : 0;
}
- /* XXX horrible, need to use some mempool, stack or something :) */
auce->uuids.nbr_uuids++;
- if (auce->uuids.uuids) {
- auce->uuids.uuids = MEM_reallocN_id(auce->uuids.uuids, sizeof(*auce->uuids.uuids) * (size_t)auce->uuids.nbr_uuids, __func__);
- }
- else {
- auce->uuids.uuids = MEM_mallocN(sizeof(*auce->uuids.uuids) * (size_t)auce->uuids.nbr_uuids, __func__);
+ BKE_asset_uuid_print(id->uuid);
+ if (auce->uuids.nbr_uuids > auce->allocated_uuids) {
+ auce->allocated_uuids += 16;
+ BLI_assert(auce->uuids.nbr_uuids < auce->allocated_uuids);
+
+ const size_t allocsize = sizeof(*auce->uuids.uuids) * (size_t)auce->allocated_uuids;
+ auce->uuids.uuids = auce->uuids.uuids ?
+ MEM_reallocN_id(auce->uuids.uuids, allocsize, __func__) :
+ MEM_mallocN(allocsize, __func__);
}
auce->uuids.uuids[auce->uuids.nbr_uuids - 1] = *id->uuid;
}
@@ -1381,6 +1413,7 @@ static int wm_assets_reload_exec(bContext *C, wmOperator *op)
* - cleanup indirect dependencies IDs with zero users.
*/
Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
ListBase engines = {NULL};
@@ -1461,7 +1494,7 @@ static int wm_assets_reload_exec(bContext *C, wmOperator *op)
}
}
- lib_relocate_do(bmain, lapp_data, op->reports, auce->ae->type, do_reload);
+ lib_relocate_do(bmain, scene, NULL, lapp_data, op->reports, auce->ae->type, do_reload);
wm_link_append_data_free(lapp_data);
BLI_ghash_free(libraries, MEM_freeN, NULL);
@@ -1476,19 +1509,6 @@ static int wm_assets_reload_exec(bContext *C, wmOperator *op)
}
BLI_freelistN(&engines);
- BKE_main_lib_objects_recalc_all(bmain);
- IMB_colormanagement_check_file_config(bmain);
-
- /* important we unset, otherwise these object wont
- * link into other scenes from this blend file */
- BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
-
- /* recreate dependency graph to include new objects */
- DAG_scene_relations_rebuild(bmain, CTX_data_scene(C));
-
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free();
-
WM_event_add_notifier(C, NC_WINDOW, NULL);
G.f &= ~G_ASSETS_NEED_RELOAD;
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 1de92c09af1..c96d0199d24 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -57,7 +57,7 @@
#include "BLO_writefile.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_blender.h"
#include "BKE_blender_undo.h"
#include "BKE_context.h"
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 206007b8d8b..ca841954b16 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -63,6 +63,8 @@ if(WIN32 AND NOT UNIX)
COMPONENT Blenderplayer
DESTINATION ".")
+add_cc_flags_custom_test(blenderplayer)
+
elseif(APPLE)
add_executable(blenderplayer ${EXETYPE} bad_level_call_stubs/stubs.c)
# setup Info.plist
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 4d3ad159231..644c84fa3fa 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -247,7 +247,7 @@ bool RE_HasFakeLayer(RenderResult *res) RET_ZERO
/* zbuf.c stub */
void antialias_tagbuf(int xsize, int ysize, char *rectmove) RET_NONE
-void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect) RET_NONE
+void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, const float *imgrect, float *vecbufrect, const float *zbufrect) RET_NONE
/* imagetexture.c stub */
void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result) RET_NONE
@@ -309,6 +309,8 @@ void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot)
void WM_autosave_init(wmWindowManager *wm) RET_NONE
void WM_jobs_kill_all_except(struct wmWindowManager *wm, void *owner) RET_NONE
+void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports) RET_NONE
+
char *WM_clipboard_text_get(bool selection, int *r_len) RET_NULL
char *WM_clipboard_text_get_firstline(bool selection, int *r_len) RET_NULL
void WM_clipboard_text_set(const char *buf, bool selection) RET_NONE
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 4e8dd6f9fd3..7acea43d1f5 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -222,6 +222,8 @@ if(WITH_BUILDINFO)
add_dependencies(buildinfoobj buildinfo)
endif()
+add_cc_flags_custom_test(blender)
+
# message(STATUS "Configuring blender")
if(WITH_PYTHON_MODULE)
add_definitions(-DWITH_PYTHON_MODULE)
@@ -244,7 +246,7 @@ if(WITH_PYTHON_MODULE)
set_target_properties(
blender
PROPERTIES
- MACOSX_BUNDLE
+ MACOSX_BUNDLE TRUE
LINK_FLAGS_RELEASE "${PLATFORM_LINKFLAGS}"
LINK_FLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG}"
)
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 5596402b41b..741fcec6cfc 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -54,7 +54,7 @@
/* mostly init functions */
#include "BKE_appdir.h"
-#include "BKE_asset.h"
+#include "BKE_asset_engine.h"
#include "BKE_blender.h"
#include "BKE_brush.h"
#include "BKE_context.h"
@@ -172,9 +172,9 @@ static void callback_main_atexit(void *user_data)
#ifdef WIN32
if (app_init_data->argv) {
while (app_init_data->argv_num) {
- free(app_init_data->argv[--app_init_data->argv_num]);
+ free((void *)app_init_data->argv[--app_init_data->argv_num]);
}
- free(app_init_data->argv);
+ free((void *)app_init_data->argv);
app_init_data->argv = NULL;
}
#endif
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index c89cdea4e29..c3c76a0d1d3 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -739,8 +739,6 @@ static const char arg_handle_debug_mode_generic_set_doc_handlers[] =
"\n\tEnable debug messages for event handling";
static const char arg_handle_debug_mode_generic_set_doc_wm[] =
"\n\tEnable debug messages for the window manager, also prints every operator call";
-static const char arg_handle_debug_mode_generic_set_doc_all[] =
-"\n\tEnable all debug messages (excludes libmv)";
static const char arg_handle_debug_mode_generic_set_doc_jobs[] =
"\n\tEnable time profiling for background jobs.";
static const char arg_handle_debug_mode_generic_set_doc_gpu[] =
@@ -758,6 +756,20 @@ static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUS
return 0;
}
+static const char arg_handle_debug_mode_all_doc[] =
+"\n\tEnable all debug messages";
+static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ G.debug |= G_DEBUG_ALL;
+#ifdef WITH_LIBMV
+ libmv_startDebugLogging();
+#endif
+#ifdef WITH_CYCLES_LOGGING
+ CCL_start_debug_logging();
+#endif
+ return 0;
+}
+
#ifdef WITH_LIBMV
static const char arg_handle_debug_mode_libmv_doc[] =
"\n\tEnable debug messages from libmv library"
@@ -1791,8 +1803,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
CB_EX(arg_handle_debug_mode_generic_set, handlers), (void *)G_DEBUG_HANDLERS);
BLI_argsAdd(ba, 1, NULL, "--debug-wm",
CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM);
- BLI_argsAdd(ba, 1, NULL, "--debug-all",
- CB_EX(arg_handle_debug_mode_generic_set, all), (void *)G_DEBUG_ALL);
+ BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL);
BLI_argsAdd(ba, 1, NULL, "--debug-fpe",
CB(arg_handle_debug_fpe_set), NULL);
diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp
index 25936b34fde..fd2e723741c 100644
--- a/source/gameengine/GameLogic/SCA_PythonController.cpp
+++ b/source/gameengine/GameLogic/SCA_PythonController.cpp
@@ -163,7 +163,9 @@ void SCA_PythonController::SetNamespace(PyObject* pythondictionary)
/* Without __file__ set the sys.argv[0] is used for the filename
* which ends up with lines from the blender binary being printed in the console */
- PyDict_SetItemString(m_pythondictionary, "__file__", PyUnicode_From_STR_String(m_scriptName));
+ PyObject *value = PyUnicode_From_STR_String(m_scriptName);
+ PyDict_SetItemString(m_pythondictionary, "__file__", value);
+ Py_DECREF(value);
}
#endif
diff --git a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp
index 19aae46f2a3..9a96a7b0334 100644
--- a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp
+++ b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp
@@ -113,11 +113,15 @@ PyObject *SCA_PythonKeyboard::pyattr_get_events(void *self_v, const KX_PYATTRIBU
{
SCA_PythonKeyboard* self = static_cast<SCA_PythonKeyboard*>(self_v);
- for (int i=SCA_IInputDevice::KX_BEGINKEY; i<=SCA_IInputDevice::KX_ENDKEY; i++)
- {
+ for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) {
const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
-
- PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status));
+ PyObject *key = PyLong_FromLong(i);
+ PyObject *value = PyLong_FromLong(inevent.m_status);
+
+ PyDict_SetItem(self->m_event_dict, key, value);
+
+ Py_DECREF(key);
+ Py_DECREF(value);
}
Py_INCREF(self->m_event_dict);
return self->m_event_dict;
@@ -129,12 +133,18 @@ PyObject *SCA_PythonKeyboard::pyattr_get_active_events(void *self_v, const KX_PY
PyDict_Clear(self->m_event_dict);
- for (int i=SCA_IInputDevice::KX_BEGINKEY; i<=SCA_IInputDevice::KX_ENDKEY; i++)
- {
+ for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) {
const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
- if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS)
- PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status));
+ if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) {
+ PyObject *key = PyLong_FromLong(i);
+ PyObject *value = PyLong_FromLong(inevent.m_status);
+
+ PyDict_SetItem(self->m_event_dict, key, value);
+
+ Py_DECREF(key);
+ Py_DECREF(value);
+ }
}
Py_INCREF(self->m_event_dict);
return self->m_event_dict;
diff --git a/source/gameengine/GameLogic/SCA_PythonMouse.cpp b/source/gameengine/GameLogic/SCA_PythonMouse.cpp
index 1617f714113..184b306a665 100644
--- a/source/gameengine/GameLogic/SCA_PythonMouse.cpp
+++ b/source/gameengine/GameLogic/SCA_PythonMouse.cpp
@@ -96,11 +96,15 @@ PyObject *SCA_PythonMouse::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_
{
SCA_PythonMouse* self = static_cast<SCA_PythonMouse*>(self_v);
- for (int i=SCA_IInputDevice::KX_BEGINMOUSE; i<=SCA_IInputDevice::KX_ENDMOUSE; i++)
- {
- const SCA_InputEvent & inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
-
- PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status));
+ for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) {
+ const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
+ PyObject *key = PyLong_FromLong(i);
+ PyObject *value = PyLong_FromLong(inevent.m_status);
+
+ PyDict_SetItem(self->m_event_dict, key, value);
+
+ Py_DECREF(key);
+ Py_DECREF(value);
}
Py_INCREF(self->m_event_dict);
return self->m_event_dict;
@@ -112,12 +116,19 @@ PyObject *SCA_PythonMouse::pyattr_get_active_events(void *self_v, const KX_PYATT
PyDict_Clear(self->m_event_dict);
- for (int i=SCA_IInputDevice::KX_BEGINMOUSE; i<=SCA_IInputDevice::KX_ENDMOUSE; i++)
- {
- const SCA_InputEvent & inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
+ for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) {
+ const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i);
- if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS)
- PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status));
+ if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) {
+
+ PyObject *key = PyLong_FromLong(i);
+ PyObject *value = PyLong_FromLong(inevent.m_status);
+
+ PyDict_SetItem(self->m_event_dict, key, value);
+
+ Py_DECREF(key);
+ Py_DECREF(value);
+ }
}
Py_INCREF(self->m_event_dict);
return self->m_event_dict;
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index 9c3f94f1918..d033afacc08 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -709,7 +709,7 @@ int main(
{
i++;
if ( (i + 1) <= validArguments )
- parentWindow = atoi(argv[i++]);
+ parentWindow = (GHOST_TEmbedderWindowID)atoll(argv[i++]);
else {
error = true;
printf("error: too few options for parent window argument.\n");
diff --git a/source/tools b/source/tools
new file mode 160000
+Subproject 373945d0978b6601c55c9d5879e0f488b18515c